1
0
Fork 0
mirror of synced 2025-09-23 04:08:33 +00:00

deprecate multi returns

This commit is contained in:
dark64 2022-06-21 15:03:53 +02:00
parent bd69368f91
commit b7e787dfd1
184 changed files with 1801 additions and 3051 deletions

View file

@ -277,7 +277,7 @@ fn parse_value<T: Field>(
.map_err(|_| Error::Type(format!("Could not parse `{}` to u64 type", s))),
(ConcreteType::Boolean, serde_json::Value::Bool(b)) => Ok(Value::Boolean(b)),
(ConcreteType::Array(array_type), serde_json::Value::Array(a)) => {
let size = array_type.size;
let size = *array_type.size;
if a.len() != size as usize {
Err(Error::Type(format!(
"Expected array of size {}, found array of size {}",

View file

@ -12,7 +12,7 @@ Arguments are passed by value.
{{#include ../../../zokrates_cli/examples/book/side_effects.zok}}
```
Generic paramaters, if any, must be compile-time constants. They are inferred by the compiler if that is possible, but can also be provided explicitly.
Generic parameters, if any, must be compile-time constants. They are inferred by the compiler if that is possible, but can also be provided explicitly.
```zokrates
{{#include ../../../zokrates_cli/examples/book/generic_call.zok}}

View file

@ -18,18 +18,4 @@ The generic parameters can be provided explicitly, especially when they cannot b
```zokrates
{{#include ../../../zokrates_cli/examples/book/explicit_generic_parameters.zok}}
```
Functions can return multiple values by providing them as a comma-separated list.
```zokrates
{{#include ../../../zokrates_cli/examples/book/multi_return.zok}}
```
### Variable declaration
When defining a variable as the return value of a function, types are provided when the variable needs to be declared:
```zokrates
{{#include ../../../zokrates_cli/examples/book/multi_def.zok}}
```

View file

@ -71,8 +71,8 @@ ZoKrates offers a special shorthand syntax to initialize an array with a constan
The following code provides examples for declaration and initialization:
```zokrates
field[3] a = [1, 2, 3] // initialize a field array with field values
bool[13] b = [false; 13] // initialize a bool array with value false
field[3] a = [1, 2, 3] // initialize a field array with field values
bool[13] b = [false; 13] // initialize a bool array with value false
```
#### Multidimensional Arrays
@ -132,8 +132,8 @@ A struct definition starts with the `struct` keyword followed by a name. Afterwa
```zokrates
struct Point {
field x
field y
field x
field y
}
```

View file

@ -59,11 +59,9 @@ In this example, the ABI specification is:
"type":"field"
}
],
"outputs":[
{
"type":"field"
}
]
"output": {
"type":"field"
}
}
```

View file

@ -24,7 +24,7 @@ import { initialize } from 'zokrates-js/node'; // or require('zokrates-js/node')
## Example
```js
initialize().then((zokratesProvider) => {
const source = "def main(private field a) -> field: return a * a";
const source = "def main(private field a) -> field { return a * a; }";
// compilation
const artifacts = zokratesProvider.compile(source);
@ -88,7 +88,7 @@ Returns: `CompilationArtifacts`
Compilation:
```js
const artifacts = zokratesProvider.compile("def main() -> (): return");
const artifacts = zokratesProvider.compile("def main() { return; }");
```
Compilation with custom options:
@ -135,7 +135,7 @@ Returns: `ComputationResult`
**Example:**
```js
const code = 'def main(private field a) -> (field): return a * a';
const code = 'def main(private field a) -> field { return a * a; }';
const artifacts = zokratesProvider.compile(code);
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);

View file

@ -11,5 +11,5 @@ def fill<R, C>(field v) -> matrix<R, C> {
def main(uint32 a, uint32 b) -> (UInt32Array<2>, matrix<2, 4>) {
UInt32Array<2> res = [a, b];
matrix<2, 4> m = fill(1);
return res, m;
return (res, m);
}

View file

@ -12,5 +12,5 @@ def buzz<N>() -> Buzz<N> {
def main(matrix_2x4 m) -> (Buzz<2>, matrix_2x4) {
Buzz<2> b = buzz::<2>();
return b, m;
return (b, m);
}

View file

@ -1,4 +1,4 @@
def main() -> (u32[3]) {
def main() -> u32[3] {
u32[3] a = [1, 2, 3];
u32[3] c = [4, 5, 6];
for u32 i in 0..3 {

View file

@ -1,4 +1,4 @@
def main(bool[3] a) -> (field[3]) {
def main(bool[3] a) -> field[3] {
bool[3] c = [true, true || false, true];
a[1] = true || a[2];
a[2] = a[0];

View file

@ -1,3 +1,3 @@
def main(field value) -> (field[3]) {
def main(field value) -> field[3] {
return [value, value, value];
}

View file

@ -1,4 +1,4 @@
def main(field[10][10][10] a, u32 i, u32 j, u32 k) -> (field[3]) {
def main(field[10][10][10] a, u32 i, u32 j, u32 k) -> field[3] {
a[i][j][k] = 42;
field[3][3] b = [[1, 2, 3], [1, 2, 3], [1, 2, 3]];
return b[0];

File diff suppressed because one or more lines are too long

View file

@ -7,6 +7,6 @@ def main() -> (field, field) {
field[3] a = [0, 0, 0];
field res = foo(a);
assert(a[1] == 0);
return res, a[1];
return (res, a[1]);
}

View file

@ -7,5 +7,5 @@ def main(field a) -> (field, field) {
field r = foo(a);
result[1] = r;
assert(result[1] == r);
return result[1], r;
return (result[1], r);
}

View file

@ -2,12 +2,8 @@ def foo() -> u32 {
return 0;
}
def bar() -> (u32, u32) {
return 0, 0;
}
def main(u32[1] a, u32 b) {
def main(u32[1] a, (u32,) b) {
a[0] = foo();
a[0], b = bar();
b.0 = foo();
return;
}

View file

@ -1,4 +1,4 @@
def main() -> () {
def main() {
assert(1f + 1f == 2f);
return;
return;
}

View file

@ -1,14 +1,16 @@
def swap(u32 a, u32 b, bool c) -> (u32, u32) {
u32 a_prime = c ? b : a;
b = c ? a : b;
return a_prime, b;
return (a_prime, b);
}
def bubblesort<N>(u32[N] a) -> u32[N] {
for u32 i in 0..(N-1) {
for u32 j in 0..(N-1-i) {
bool need_swap = a[j + 1] < a[j];
a[j], a[j + 1] = swap(a[j], a[j + 1], need_swap);
(u32, u32) swapped = swap(a[j], a[j + 1], need_swap);
a[j] = swapped.0;
a[j + 1] = swapped.1;
}
}
return a;

View file

@ -1,7 +1,7 @@
def main() {
// declare and define `my_variable`
field my_variable = 2;
// redefine `my_variable`
my_variable = 3;
return;
field my_variable = 2;
// redefine `my_variable`
my_variable = 3;
return;
}

View file

@ -1,8 +1,8 @@
def main() -> u32 {
u32 res = 0;
for u32 i in 0..4 {
for u32 j in i..5 {
res = res + i;
for u32 j in i..5 {
res = res + i;
}
}
return res;

View file

@ -1,8 +1,8 @@
def main() -> u32 {
u32 a = 0;
for u32 i in 0..5 {
a = a + i;
}
// return i <- not allowed
return a;
u32 a = 0;
for u32 i in 0..5 {
a = a + i;
}
// return i <- not allowed
return a;
}

View file

@ -1,9 +1,9 @@
def sum<N>(field[N] a) -> field {
field res = 0;
for u32 i in 0..N {
res = res + a[i];
}
return res;
field res = 0;
for u32 i in 0..N {
res = res + a[i];
}
return res;
}
def main(field[3] a) -> field {

View file

@ -1,11 +0,0 @@
def foo() -> (field, field) {
return 21, 42;
}
def main() {
// a is declared here
field a = 1;
// b is declared here
a, field b = foo();
return;
}

View file

@ -1,3 +0,0 @@
def main() -> (field, field[3]) {
return 1, [2, 3, 4];
}

View file

@ -1,8 +1,8 @@
def main() -> field {
field a = 2;
// field a = 3 <- not allowed
for u32 i in 0..5 {
// field a = 7 <- not allowed
}
return a;
field a = 2;
// field a = 3 <- not allowed
for u32 i in 0..5 {
// field a = 7 <- not allowed
}
return a;
}

View file

@ -1,3 +1,3 @@
def main(field a, field b) -> (bool) {
def main(field a, field b) -> bool {
return !(a == b);
}

View file

@ -1,10 +1,10 @@
def main() {
// `255` is infered to `255f`, and the addition happens between field elements
assert(255 + 1f == 256);
// `255` is infered to `255f`, and the addition happens between field elements
assert(255 + 1f == 256);
// `255` is infered to `255u8`, and the addition happens between u8
// This causes an overflow
assert(255 + 1u8 == 0);
// `255` is infered to `255u8`, and the addition happens between u8
// This causes an overflow
assert(255 + 1u8 == 0);
return;
return;
}

View file

@ -15,5 +15,5 @@ def main(private u32[16] preimage, u32 bitNum) -> (u32[8], bool) {
preimageBits[i*32 + bit] = val[bit];
}
}
return sha256(preimage[0..8], preimage[8..16]), preimageBits[bitNum];
return (sha256(preimage[0..8], preimage[8..16]), preimageBits[bitNum]);
}

View file

@ -1,9 +1,9 @@
struct Point {
field x;
field y;
field x;
field y;
}
def main(field a) -> (Point) {
def main(field a) -> Point {
Point p = Point { x: 1, y: 0 };
p.x = a;
p.y = p.x;

View file

@ -1,10 +1,10 @@
struct Point {
field x;
field y;
field x;
field y;
}
def main() -> (Point) {
Point p = Point { x: 1, y: 0 };
return p;
def main() -> Point {
Point p = Point { x: 1, y: 0 };
return p;
}

View file

@ -1,16 +1,16 @@
struct Bar<N> {
field[N] c;
bool d;
field[N] c;
bool d;
}
struct Foo<P> {
Bar<P> a;
bool b;
Bar<P> a;
bool b;
}
def main() -> (Foo<2>) {
Foo<2>[2] f = [Foo { a: Bar { c: [0, 0], d: false }, b: true}, Foo { a: Bar {c: [0, 0], d: false}, b: true }];
f[0].a.c = [42, 43];
return f[0];
def main() -> Foo<2> {
Foo<2>[2] f = [Foo { a: Bar { c: [0, 0], d: false }, b: true}, Foo { a: Bar {c: [0, 0], d: false}, b: true }];
f[0].a.c = [42, 43];
return f[0];
}

View file

@ -1,6 +1,6 @@
def main() -> bool {
(field[2], bool) v = ([1, 2], true);
v.0 = [42, 43];
return v.1;
(field[2], bool) v = ([1, 2], true);
v.0 = [42, 43];
return v.1;
}

View file

@ -1,12 +1,12 @@
def foo() -> (field, field[3]) {
return 1, [2, 3, 4];
return (1, [2, 3, 4]);
}
def foo() -> (field, field) {
return 1, 2;
return (1, 2);
}
def main() {
field a, field[3] b = foo();
(field, field[3]) a = foo();
return;
}

View file

@ -2,6 +2,5 @@ def assert() {
return;
}
def main():
return

View file

@ -1,6 +1,6 @@
struct Foo {}
struct Bar {}
def main() -> (Foo) {
def main() -> Foo {
return Bar {};
}

View file

@ -4,7 +4,7 @@ import "hashes/utils/256bitsDirectionHelper" as multiplex;
const u32 DEPTH = 3;
def select(bool condition, u32[8] left, u32[8] right) -> (u32[8], u32[8]) {
return condition ? right : left, condition ? left : right;
return (condition ? right : left, condition ? left : right);
}
// Merke-Tree inclusion proof for tree depth 4 using sha256
@ -16,8 +16,8 @@ def main(u32[8] root, private u32[8] leaf, private bool[DEPTH] directionSelector
// Loop up the tree
for u32 i in 0..DEPTH {
u32[8] left, u32[8] right = select(directionSelector[i], digest, path[i]);
digest = hash(left, right);
(u32[8], u32[8]) s = select(directionSelector[i], digest, path[i]);
digest = hash(s.0, s.1);
}
return digest == root;

View file

@ -1,9 +0,0 @@
def foo(field a) -> (field, field, field, field) {
field b = 12 * a;
return a, 2 * a, 5 * b, a * b;
}
def main(field i) {
field x, field y, field z, field t = foo(i);
return;
}

View file

@ -1,8 +0,0 @@
def foo() -> (field, field) {
return 1, 2;
}
def main() -> (field, field) {
field a, field b = foo();
return a + b, b - a;
}

View file

@ -1,9 +1,9 @@
def foo(field a, field b) -> (field, field) {
assert(a == b);
return a, b;
return (a, b);
}
def main() -> field {
field a, field b = foo(1, 1);
return a + b;
(field, field) v = foo(1, 1);
return v.0 + v.1;
}

View file

@ -1,4 +1,4 @@
def main((field, field) p, (field, field) q) -> ((field, field)) {
def main((field, field) p, (field, field) q) -> (field, field) {
field a = 42;
field d = 21;

View file

@ -8,7 +8,7 @@ struct Foo {
bool b;
}
def main() -> (((field[2], bool), bool)) {
def main() -> ((field[2], bool), bool) {
((field[2], bool), bool)[2] f = [
(([0, 0], false), true),
(([0, 0], false), true)

View file

@ -8,7 +8,7 @@ use zokrates_abi::Encode;
use zokrates_core::ir;
use zokrates_core::ir::ProgEnum;
use zokrates_core::typed_absy::abi::Abi;
use zokrates_core::typed_absy::types::{ConcreteSignature, ConcreteType};
use zokrates_core::typed_absy::types::{ConcreteSignature, ConcreteType, GTupleType};
use zokrates_field::Field;
pub fn subcommand() -> App<'static, 'static> {
@ -103,7 +103,9 @@ fn cli_compute<T: Field, I: Iterator<Item = ir::Statement<T>>>(
}
false => ConcreteSignature::new()
.inputs(vec![ConcreteType::FieldElement; ir_prog.arguments.len()])
.outputs(vec![ConcreteType::FieldElement; ir_prog.return_count]),
.output(ConcreteType::Tuple(GTupleType::new(
vec![ConcreteType::FieldElement; ir_prog.return_count],
))),
};
use zokrates_abi::Inputs;
@ -165,7 +167,7 @@ fn cli_compute<T: Field, I: Iterator<Item = ir::Statement<T>>>(
use zokrates_abi::Decode;
let results_json_value: serde_json::Value =
zokrates_abi::Values::decode(witness.return_values(), signature.outputs).into_serde_json();
zokrates_abi::Value::decode(witness.return_values(), *signature.output).into_serde_json();
if verbose {
println!("\nWitness: \n{}\n", results_json_value);

View file

@ -183,16 +183,13 @@ impl<'ast> From<pest::FunctionDefinition<'ast>> for absy::SymbolDeclarationNode<
.into_iter()
.map(|p| absy::UnresolvedTypeNode::from(p.ty))
.collect(),
)
.outputs(
function
.returns
.clone()
.into_iter()
.map(absy::UnresolvedTypeNode::from)
.collect(),
);
let signature = match function.return_type {
Some(ret_ty) => signature.output(absy::UnresolvedTypeNode::from(ret_ty)),
None => signature,
};
let id = function.id.span.as_str();
let function = absy::Function {
@ -261,92 +258,28 @@ fn statements_from_statement(statement: pest::Statement) -> Vec<absy::StatementN
fn statements_from_definition(definition: pest::DefinitionStatement) -> Vec<absy::StatementNode> {
use crate::absy::NodeValue;
let lhs = definition.lhs;
let e: absy::ExpressionNode = absy::ExpressionNode::from(definition.expression);
match lhs.len() {
1 => {
// Definition or assignment
let a = lhs[0].clone();
let e: absy::ExpressionNode = absy::ExpressionNode::from(definition.expression);
match a {
pest::TypedIdentifierOrAssignee::TypedIdentifier(i) => {
let declaration = absy::Statement::Declaration(
absy::Variable::new(
i.identifier.span.as_str(),
absy::UnresolvedTypeNode::from(i.ty),
)
.span(i.identifier.span.clone()),
)
.span(definition.span.clone());
let s = match e.value {
absy::Expression::FunctionCall(..) => absy::Statement::MultipleDefinition(
vec![absy::AssigneeNode::from(i.identifier.clone())],
e,
),
_ => absy::Statement::Definition(
absy::AssigneeNode::from(i.identifier.clone()),
e,
),
};
vec![declaration, s.span(definition.span)]
}
pest::TypedIdentifierOrAssignee::Assignee(a) => {
let s = match e.value {
absy::Expression::FunctionCall(..) => absy::Statement::MultipleDefinition(
vec![absy::AssigneeNode::from(a)],
e,
),
_ => absy::Statement::Definition(absy::AssigneeNode::from(a), e),
};
vec![s.span(definition.span)]
}
}
}
_ => {
// Multidefinition
let declarations = lhs.clone().into_iter().filter_map(|i| match i {
pest::TypedIdentifierOrAssignee::TypedIdentifier(i) => {
let ty = i.ty;
let id = i.identifier;
Some(
absy::Statement::Declaration(
absy::Variable::new(
id.span.as_str(),
absy::UnresolvedTypeNode::from(ty),
)
.span(id.span),
)
.span(i.span),
)
}
_ => None,
});
let lhs = lhs
.into_iter()
.map(|i| match i {
pest::TypedIdentifierOrAssignee::TypedIdentifier(i) => {
absy::Assignee::Identifier(i.identifier.span.as_str())
.span(i.identifier.span)
}
pest::TypedIdentifierOrAssignee::Assignee(a) => absy::AssigneeNode::from(a),
})
.collect();
let multi_def = absy::Statement::MultipleDefinition(
lhs,
absy::ExpressionNode::from(definition.expression),
match lhs {
pest::TypedIdentifierOrAssignee::TypedIdentifier(i) => {
let declaration = absy::Statement::Declaration(
absy::Variable::new(
i.identifier.span.as_str(),
absy::UnresolvedTypeNode::from(i.ty),
)
.span(i.identifier.span.clone()),
)
.span(definition.span);
.span(definition.span.clone());
declarations.chain(std::iter::once(multi_def)).collect()
let definition =
absy::Statement::Definition(absy::AssigneeNode::from(i.identifier.clone()), e)
.span(definition.span);
vec![declaration, definition]
}
pest::TypedIdentifierOrAssignee::Assignee(a) => {
vec![absy::Statement::Definition(absy::AssigneeNode::from(a), e).span(definition.span)]
}
}
}
@ -355,17 +288,8 @@ impl<'ast> From<pest::ReturnStatement<'ast>> for absy::StatementNode<'ast> {
fn from(statement: pest::ReturnStatement<'ast>) -> absy::StatementNode<'ast> {
use crate::absy::NodeValue;
absy::Statement::Return(
absy::ExpressionList {
expressions: statement
.expressions
.into_iter()
.map(absy::ExpressionNode::from)
.collect(),
}
.span(statement.span.clone()),
)
.span(statement.span)
absy::Statement::Return(statement.expression.map(absy::ExpressionNode::from))
.span(statement.span)
}
}
@ -914,18 +838,13 @@ mod tests {
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
absy::Function {
arguments: vec![],
statements: vec![absy::Statement::Return(
absy::ExpressionList {
expressions: vec![
absy::Expression::IntConstant(42usize.into()).into()
],
}
.into(),
)
statements: vec![absy::Statement::Return(Some(
absy::Expression::IntConstant(42usize.into()).into(),
))
.into()],
signature: UnresolvedSignature::new()
.inputs(vec![])
.outputs(vec![UnresolvedType::FieldElement.mock()]),
.output(UnresolvedType::FieldElement.mock()),
}
.into(),
)),
@ -945,16 +864,13 @@ mod tests {
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
absy::Function {
arguments: vec![],
statements: vec![absy::Statement::Return(
absy::ExpressionList {
expressions: vec![absy::Expression::BooleanConstant(true).into()],
}
.into(),
)
statements: vec![absy::Statement::Return(Some(
absy::Expression::BooleanConstant(true).into(),
))
.into()],
signature: UnresolvedSignature::new()
.inputs(vec![])
.outputs(vec![UnresolvedType::Boolean.mock()]),
.output(UnresolvedType::Boolean.mock()),
}
.into(),
)),
@ -992,21 +908,16 @@ mod tests {
)
.into(),
],
statements: vec![absy::Statement::Return(
absy::ExpressionList {
expressions: vec![
absy::Expression::IntConstant(42usize.into()).into()
],
}
.into(),
)
statements: vec![absy::Statement::Return(Some(
absy::Expression::IntConstant(42usize.into()).into(),
))
.into()],
signature: UnresolvedSignature::new()
.inputs(vec![
UnresolvedType::FieldElement.mock(),
UnresolvedType::Boolean.mock(),
])
.outputs(vec![UnresolvedType::FieldElement.mock()]),
.output(UnresolvedType::FieldElement.mock()),
}
.into(),
)),
@ -1031,13 +942,7 @@ mod tests {
absy::Variable::new("a", ty.clone().mock()).into(),
)
.into()],
statements: vec![absy::Statement::Return(
absy::ExpressionList {
expressions: vec![],
}
.into(),
)
.into()],
statements: vec![absy::Statement::Return(None).into()],
signature: UnresolvedSignature::new().inputs(vec![ty.mock()]),
}
.into(),
@ -1101,13 +1006,9 @@ mod tests {
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
absy::Function {
arguments: vec![],
statements: vec![absy::Statement::Return(
absy::ExpressionList {
expressions: vec![expression.into()],
}
.into(),
)
.into()],
statements: vec![
absy::Statement::Return(Some(expression.into())).into()
],
signature: UnresolvedSignature::new(),
}
.into(),
@ -1239,20 +1140,19 @@ mod tests {
let span = Span::new("", 0, 0).unwrap();
// For different definitions, we generate declarations
// Case 1: `id = expr` where `expr` is not a function call
// This is a simple assignment, doesn't implicitely declare a variable
// A `Definition` is generated and no `Declaration`s
// Case 1: `id = expr`
// This is a simple assignment to an already existing variable
// A definition is generated
let definition = pest::DefinitionStatement {
lhs: vec![pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee {
lhs: pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee {
id: pest::IdentifierExpression {
value: String::from("a"),
span: span.clone(),
},
accesses: vec![],
span: span.clone(),
})],
}),
expression: pest::Expression::Literal(pest::LiteralExpression::DecimalLiteral(
pest::DecimalLiteralExpression {
value: pest::DecimalNumber {
@ -1275,71 +1175,20 @@ mod tests {
}
};
// Case 2: `id = expr` where `expr` is a function call
// A MultiDef is generated
// Case 2: `type id = expr`
// A declaration and a definition is generated
let definition = pest::DefinitionStatement {
lhs: vec![pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee {
id: pest::IdentifierExpression {
lhs: pest::TypedIdentifierOrAssignee::TypedIdentifier(pest::TypedIdentifier {
ty: pest::Type::Basic(pest::BasicType::Field(pest::FieldType {
span: span.clone(),
})),
identifier: pest::IdentifierExpression {
value: String::from("a"),
span: span.clone(),
},
accesses: vec![],
span: span.clone(),
})],
expression: pest::Expression::Postfix(pest::PostfixExpression {
base: box pest::Expression::Identifier(pest::IdentifierExpression {
value: String::from("foo"),
span: span.clone(),
}),
accesses: vec![pest::Access::Call(pest::CallAccess {
explicit_generics: None,
arguments: pest::Arguments {
expressions: vec![],
span: span.clone(),
},
span: span.clone(),
})],
span: span.clone(),
}),
span: span.clone(),
};
let statements: Vec<absy::StatementNode> = statements_from_definition(definition);
assert_eq!(statements.len(), 1);
match &statements[0].value {
absy::Statement::MultipleDefinition(..) => {}
s => {
panic!("should be a Definition, found {}", s);
}
};
// Case 3: `ids = expr` where `expr` is a function call
// This implicitely declares all variables which are type annotated
// `field a, b = foo()`
let definition = pest::DefinitionStatement {
lhs: vec![
pest::TypedIdentifierOrAssignee::TypedIdentifier(pest::TypedIdentifier {
ty: pest::Type::Basic(pest::BasicType::Field(pest::FieldType {
span: span.clone(),
})),
identifier: pest::IdentifierExpression {
value: String::from("a"),
span: span.clone(),
},
span: span.clone(),
}),
pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee {
id: pest::IdentifierExpression {
value: String::from("b"),
span: span.clone(),
},
accesses: vec![],
span: span.clone(),
}),
],
expression: pest::Expression::Postfix(pest::PostfixExpression {
base: box pest::Expression::Identifier(pest::IdentifierExpression {
value: String::from("foo"),
@ -1361,10 +1210,10 @@ mod tests {
let statements: Vec<absy::StatementNode> = statements_from_definition(definition);
assert_eq!(statements.len(), 2);
match &statements[1].value {
absy::Statement::MultipleDefinition(..) => {}
s => {
panic!("should be a Definition, found {}", s);
match (&statements[0].value, &statements[1].value) {
(absy::Statement::Declaration(..), absy::Statement::Definition(..)) => {}
_ => {
panic!("should be a (Declaration, Definition)");
}
};
}

View file

@ -384,7 +384,7 @@ impl<'ast> fmt::Display for Assignee<'ast> {
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq)]
pub enum Statement<'ast> {
Return(ExpressionListNode<'ast>),
Return(Option<ExpressionNode<'ast>>),
Declaration(VariableNode<'ast>),
Definition(AssigneeNode<'ast>, ExpressionNode<'ast>),
Assertion(ExpressionNode<'ast>, Option<String>),
@ -394,7 +394,6 @@ pub enum Statement<'ast> {
ExpressionNode<'ast>,
Vec<StatementNode<'ast>>,
),
MultipleDefinition(Vec<AssigneeNode<'ast>>, ExpressionNode<'ast>),
}
pub type StatementNode<'ast> = Node<Statement<'ast>>;
@ -402,7 +401,13 @@ pub type StatementNode<'ast> = Node<Statement<'ast>>;
impl<'ast> fmt::Display for Statement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Return(ref expr) => write!(f, "return {};", expr),
Statement::Return(ref expr) => {
write!(f, "return")?;
match expr {
Some(e) => write!(f, " {};", e),
None => write!(f, ";"),
}
}
Statement::Declaration(ref var) => write!(f, "{};", var),
Statement::Definition(ref lhs, ref rhs) => write!(f, "{} = {};", lhs, rhs),
Statement::Assertion(ref e, ref message) => {
@ -419,15 +424,6 @@ impl<'ast> fmt::Display for Statement<'ast> {
}
write!(f, "\t}}")
}
Statement::MultipleDefinition(ref ids, ref rhs) => {
for (i, id) in ids.iter().enumerate() {
write!(f, "{}", id)?;
if i < ids.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " = {};", rhs)
}
}
}
}
@ -664,23 +660,3 @@ impl<'ast> fmt::Display for Expression<'ast> {
}
}
}
/// A list of expressions, used in return statements
#[derive(Debug, Clone, PartialEq, Default)]
pub struct ExpressionList<'ast> {
pub expressions: Vec<ExpressionNode<'ast>>,
}
pub type ExpressionListNode<'ast> = Node<ExpressionList<'ast>>;
impl<'ast> fmt::Display for ExpressionList<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, param) in self.expressions.iter().enumerate() {
write!(f, "{}", param)?;
if i < self.expressions.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
}

View file

@ -85,7 +85,6 @@ use crate::absy::types::UnresolvedType;
use crate::absy::*;
impl<'ast> NodeValue for Expression<'ast> {}
impl<'ast> NodeValue for ExpressionList<'ast> {}
impl<'ast> NodeValue for Assignee<'ast> {}
impl<'ast> NodeValue for Statement<'ast> {}
impl<'ast> NodeValue for SymbolDeclaration<'ast> {}

View file

@ -85,15 +85,15 @@ mod signature {
pub struct UnresolvedSignature<'ast> {
pub generics: Vec<ConstantGenericNode<'ast>>,
pub inputs: Vec<UnresolvedTypeNode<'ast>>,
pub outputs: Vec<UnresolvedTypeNode<'ast>>,
pub output: Option<UnresolvedTypeNode<'ast>>,
}
impl<'ast> fmt::Debug for UnresolvedSignature<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Signature(inputs: {:?}, outputs: {:?})",
self.inputs, self.outputs
"Signature(inputs: {:?}, output: {:?})",
self.inputs, self.output
)
}
}
@ -107,14 +107,10 @@ mod signature {
write!(f, ", ")?;
}
}
write!(f, ") -> (")?;
for (i, t) in self.outputs.iter().enumerate() {
write!(f, "{}", t)?;
if i < self.outputs.len() - 1 {
write!(f, ", ")?;
}
match &self.output {
Some(ty) => write!(f, ") -> {}", ty),
None => write!(f, ")"),
}
write!(f, ")")
}
}
@ -133,8 +129,8 @@ mod signature {
self
}
pub fn outputs(mut self, outputs: Vec<UnresolvedTypeNode<'ast>>) -> Self {
self.outputs = outputs;
pub fn output(mut self, output: UnresolvedTypeNode<'ast>) -> Self {
self.output = Some(output);
self
}
}

View file

@ -469,7 +469,7 @@ struct Bar { field a; }
}]
))
}],
outputs: vec![]
output: ConcreteType::Tuple(GTupleType::new(vec![]))
}
);
}

View file

@ -65,66 +65,76 @@ impl FlatEmbed {
)
.into(),
])
.outputs(vec![UnresolvedType::Boolean.into()]),
.output(UnresolvedType::Boolean.into()),
FlatEmbed::Unpack => UnresolvedSignature::new()
.generics(vec!["N".into()])
.inputs(vec![UnresolvedType::FieldElement.into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::Identifier("N").into(),
)
.into()]),
.output(
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::Identifier("N").into(),
)
.into(),
),
FlatEmbed::U8ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(8).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(8).into(),
)
.into()]),
.output(
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(8).into(),
)
.into(),
),
FlatEmbed::U16ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(16).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(16).into(),
)
.into()]),
.output(
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(16).into(),
)
.into(),
),
FlatEmbed::U32ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(32).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(32).into(),
)
.into()]),
.output(
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(32).into(),
)
.into(),
),
FlatEmbed::U64ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(64).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(64).into(),
)
.into()]),
.output(
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(64).into(),
)
.into(),
),
FlatEmbed::U8FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(8).into()])
.output(UnresolvedType::Uint(8).into())
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(8).into(),
)
.into()]),
FlatEmbed::U16FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(16).into()])
.output(UnresolvedType::Uint(16).into())
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(16).into(),
)
.into()]),
FlatEmbed::U32FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(32).into()])
.output(UnresolvedType::Uint(32).into())
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(32).into(),
)
.into()]),
FlatEmbed::U64FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(64).into()])
.output(UnresolvedType::Uint(64).into())
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(64).into(),
@ -144,11 +154,13 @@ impl FlatEmbed {
)
.into(),
])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(256).into(),
)
.into()]),
.output(
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(256).into(),
)
.into(),
),
#[cfg(feature = "ark")]
FlatEmbed::SnarkVerifyBls12377 => UnresolvedSignature::new()
.generics(vec!["N".into(), "V".into()])
@ -169,7 +181,7 @@ impl FlatEmbed {
)
.into(), // 18 + (2 * n) // vk
])
.outputs(vec![UnresolvedType::Boolean.into()]),
.output(UnresolvedType::Boolean.into()),
}
}
@ -189,60 +201,48 @@ impl FlatEmbed {
GenericIdentifier::with_name("N").with_index(0),
)),
])
.outputs(vec![DeclarationType::Boolean]),
.output(DeclarationType::Boolean),
FlatEmbed::Unpack => DeclarationSignature::new()
.generics(vec![Some(DeclarationConstant::Generic(
GenericIdentifier::with_name("N").with_index(0),
))])
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::array((
.output(DeclarationType::array((
DeclarationType::Boolean,
GenericIdentifier::with_name("N").with_index(0),
))]),
))),
FlatEmbed::U8ToBits => DeclarationSignature::new()
.inputs(vec![DeclarationType::uint(8)])
.outputs(vec![DeclarationType::array((
DeclarationType::Boolean,
8u32,
))]),
.output(DeclarationType::array((DeclarationType::Boolean, 8u32))),
FlatEmbed::U16ToBits => DeclarationSignature::new()
.inputs(vec![DeclarationType::uint(16)])
.outputs(vec![DeclarationType::array((
DeclarationType::Boolean,
16u32,
))]),
.output(DeclarationType::array((DeclarationType::Boolean, 16u32))),
FlatEmbed::U32ToBits => DeclarationSignature::new()
.inputs(vec![DeclarationType::uint(32)])
.outputs(vec![DeclarationType::array((
DeclarationType::Boolean,
32u32,
))]),
.output(DeclarationType::array((DeclarationType::Boolean, 32u32))),
FlatEmbed::U64ToBits => DeclarationSignature::new()
.inputs(vec![DeclarationType::uint(64)])
.outputs(vec![DeclarationType::array((
DeclarationType::Boolean,
64u32,
))]),
.output(DeclarationType::array((DeclarationType::Boolean, 64u32))),
FlatEmbed::U8FromBits => DeclarationSignature::new()
.outputs(vec![DeclarationType::uint(8)])
.output(DeclarationType::uint(8))
.inputs(vec![DeclarationType::array((
DeclarationType::Boolean,
8u32,
))]),
FlatEmbed::U16FromBits => DeclarationSignature::new()
.outputs(vec![DeclarationType::uint(16)])
.output(DeclarationType::uint(16))
.inputs(vec![DeclarationType::array((
DeclarationType::Boolean,
16u32,
))]),
FlatEmbed::U32FromBits => DeclarationSignature::new()
.outputs(vec![DeclarationType::uint(32)])
.output(DeclarationType::uint(32))
.inputs(vec![DeclarationType::array((
DeclarationType::Boolean,
32u32,
))]),
FlatEmbed::U64FromBits => DeclarationSignature::new()
.outputs(vec![DeclarationType::uint(64)])
.output(DeclarationType::uint(64))
.inputs(vec![DeclarationType::array((
DeclarationType::Boolean,
64u32,
@ -253,10 +253,7 @@ impl FlatEmbed {
DeclarationType::array((DeclarationType::Boolean, 512u32)),
DeclarationType::array((DeclarationType::Boolean, 256u32)),
])
.outputs(vec![DeclarationType::array((
DeclarationType::Boolean,
256u32,
))]),
.output(DeclarationType::array((DeclarationType::Boolean, 256u32))),
#[cfg(feature = "ark")]
FlatEmbed::SnarkVerifyBls12377 => DeclarationSignature::new()
.generics(vec![
@ -278,7 +275,7 @@ impl FlatEmbed {
GenericIdentifier::with_name("V").with_index(1),
)), // 18 + (2 * n) // vk
])
.outputs(vec![DeclarationType::Boolean]),
.output(DeclarationType::Boolean),
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,8 @@
use crate::embed::FlatEmbed;
use crate::typed_absy::TypedProgram;
use crate::typed_absy::{
result_folder::ResultFolder,
result_folder::{fold_expression_list_inner, fold_uint_expression_inner},
Constant, TypedExpressionListInner, Types, UBitwidth, UExpressionInner,
result_folder::{fold_statement, fold_uint_expression_inner},
Constant, EmbedCall, TypedProgram, TypedStatement, UBitwidth, UExpressionInner,
};
use std::fmt;
use zokrates_field::Field;
@ -28,6 +27,46 @@ impl fmt::Display for Error {
impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantArgumentChecker {
type Error = Error;
fn fold_statement(
&mut self,
s: TypedStatement<'ast, T>,
) -> Result<Vec<TypedStatement<'ast, T>>, Self::Error> {
match s {
TypedStatement::EmbedCallDefinition(assignee, embed_call) => match embed_call {
EmbedCall {
embed: FlatEmbed::BitArrayLe,
..
} => {
let arguments = embed_call
.arguments
.into_iter()
.map(|a| self.fold_expression(a))
.collect::<Result<Vec<_>, _>>()?;
if arguments[1].is_constant() {
Ok(vec![TypedStatement::EmbedCallDefinition(
assignee,
EmbedCall {
embed: FlatEmbed::BitArrayLe,
generics: embed_call.generics,
arguments,
},
)])
} else {
Err(Error(format!(
"Cannot compare to a variable value, found `{}`",
arguments[1]
)))
}
}
embed_call => Ok(vec![TypedStatement::EmbedCallDefinition(
assignee, embed_call,
)]),
},
s => fold_statement(self, s),
}
}
fn fold_uint_expression_inner(
&mut self,
bitwidth: UBitwidth,
@ -63,33 +102,4 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantArgumentChecker {
e => fold_uint_expression_inner(self, bitwidth, e),
}
}
fn fold_expression_list_inner(
&mut self,
tys: &Types<'ast, T>,
l: TypedExpressionListInner<'ast, T>,
) -> Result<TypedExpressionListInner<'ast, T>, Error> {
match l {
TypedExpressionListInner::EmbedCall(FlatEmbed::BitArrayLe, generics, arguments) => {
let arguments = arguments
.into_iter()
.map(|a| self.fold_expression(a))
.collect::<Result<Vec<_>, _>>()?;
if arguments[1].is_constant() {
Ok(TypedExpressionListInner::EmbedCall(
FlatEmbed::BitArrayLe,
generics,
arguments,
))
} else {
Err(Error(format!(
"Cannot compare to a variable value, found `{}`",
arguments[1]
)))
}
}
l => fold_expression_list_inner(self, tys, l),
}
}
}

View file

@ -109,7 +109,7 @@ impl<'ast, T: Field> Folder<'ast, T> for ConstantResolver<'ast, T> {
#[cfg(test)]
mod tests {
use super::*;
use crate::typed_absy::types::DeclarationSignature;
use crate::typed_absy::types::{DeclarationSignature, GTupleType};
use crate::typed_absy::{
DeclarationArrayType, DeclarationFunctionKey, DeclarationType, FieldElementExpression,
GType, Identifier, TypedConstant, TypedExpression, TypedFunction, TypedFunctionSymbol,
@ -130,12 +130,12 @@ mod tests {
let const_id = "a";
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from(const_id)).into(),
])],
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let program = TypedProgram {
@ -158,7 +158,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(main),
)
@ -190,13 +190,12 @@ mod tests {
let const_id = CanonicalConstantIdentifier::new("a", "main".into());
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![BooleanExpression::Identifier(
Identifier::from(const_id.clone()),
)
.into()])],
statements: vec![TypedStatement::Return(
BooleanExpression::Identifier(Identifier::from(const_id.clone())).into(),
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
.output(DeclarationType::Boolean),
};
let program = TypedProgram {
@ -217,7 +216,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
.output(DeclarationType::Boolean),
),
TypedFunctionSymbol::Here(main),
)
@ -249,14 +248,14 @@ mod tests {
let const_id = CanonicalConstantIdentifier::new("a", "main".into());
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![UExpressionInner::Identifier(
Identifier::from(const_id.clone()),
)
.annotate(UBitwidth::B32)
.into()])],
statements: vec![TypedStatement::Return(
UExpressionInner::Identifier(Identifier::from(const_id.clone()))
.annotate(UBitwidth::B32)
.into(),
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
.output(DeclarationType::Uint(UBitwidth::B32)),
};
let program = TypedProgram {
@ -279,7 +278,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
.output(DeclarationType::Uint(UBitwidth::B32)),
),
TypedFunctionSymbol::Here(main),
)
@ -311,24 +310,26 @@ mod tests {
let const_id = CanonicalConstantIdentifier::new("a", "main".into());
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id.clone()))
.annotate(GType::FieldElement, 2u32),
UExpressionInner::Value(0u128).annotate(UBitwidth::B32),
statements: vec![TypedStatement::Return(
FieldElementExpression::Add(
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id.clone()))
.annotate(GType::FieldElement, 2u32),
UExpressionInner::Value(0u128).annotate(UBitwidth::B32),
)
.into(),
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id.clone()))
.annotate(GType::FieldElement, 2u32),
UExpressionInner::Value(1u128).annotate(UBitwidth::B32),
)
.into(),
)
.into(),
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id.clone()))
.annotate(GType::FieldElement, 2u32),
UExpressionInner::Value(1u128).annotate(UBitwidth::B32),
)
.into(),
)
.into()])],
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let program = TypedProgram {
@ -363,7 +364,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(main),
)
@ -396,12 +397,12 @@ mod tests {
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from(const_b_id.clone())).into(),
])],
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let program = TypedProgram {
@ -437,7 +438,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(main),
)
@ -522,12 +523,17 @@ mod tests {
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("foo", "main")
.signature(DeclarationSignature::new().inputs(vec![]).outputs(vec![])),
DeclarationFunctionKey::with_location("foo", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.output(DeclarationType::Tuple(GTupleType::new(vec![]))),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![],
signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
signature: DeclarationSignature::new()
.inputs(vec![])
.output(DeclarationType::Tuple(GTupleType::new(vec![]))),
}),
)
.into(),
@ -546,19 +552,19 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from(
main_const_id.clone(),
))
.into(),
])],
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
}),
)
.into(),
@ -592,19 +598,19 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from(
main_const_id.clone(),
))
.into(),
])],
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
}),
)
.into(),
@ -702,12 +708,17 @@ mod tests {
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("foo", "main")
.signature(DeclarationSignature::new().inputs(vec![]).outputs(vec![])),
DeclarationFunctionKey::with_location("foo", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.output(DeclarationType::Tuple(GTupleType::new(vec![]))),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![],
signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
signature: DeclarationSignature::new()
.inputs(vec![])
.output(DeclarationType::Tuple(GTupleType::new(vec![]))),
}),
)
.into(),
@ -748,19 +759,19 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from(
main_foo_const_id.clone(),
))
.into(),
])],
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
}),
)
.into(),
@ -823,19 +834,19 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from(
main_foo_const_id.clone(),
))
.into(),
])],
)],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
}),
)
.into(),

View file

@ -29,7 +29,7 @@ fn flatten_identifier_rec<'ast>(
id: zir::Identifier::Source(id),
_type: zir::Type::uint(bitwidth.to_usize()),
}],
typed_absy::types::ConcreteType::Array(array_type) => (0..array_type.size)
typed_absy::types::ConcreteType::Array(array_type) => (0..*array_type.size)
.flat_map(|i| {
flatten_identifier_rec(
zir::SourceIdentifier::Select(box id.clone(), i),
@ -310,26 +310,6 @@ impl<'ast, T: Field> Flattener<T> {
fold_tuple_expression(self, statements_buffer, e)
}
fn fold_expression_list(
&mut self,
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
es: typed_absy::TypedExpressionList<'ast, T>,
) -> zir::ZirExpressionList<'ast, T> {
match es.into_inner() {
typed_absy::TypedExpressionListInner::EmbedCall(embed, generics, arguments) => {
zir::ZirExpressionList::EmbedCall(
embed,
generics,
arguments
.into_iter()
.flat_map(|a| self.fold_expression(statements_buffer, a))
.collect(),
)
}
_ => unreachable!("should have been inlined"),
}
}
fn fold_conditional_expression<E: Flatten<'ast, T>>(
&mut self,
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
@ -436,11 +416,8 @@ fn fold_statement<'ast, T: Field>(
s: typed_absy::TypedStatement<'ast, T>,
) {
let res = match s {
typed_absy::TypedStatement::Return(expressions) => vec![zir::ZirStatement::Return(
expressions
.into_iter()
.flat_map(|e| f.fold_expression(statements_buffer, e))
.collect(),
typed_absy::TypedStatement::Return(expression) => vec![zir::ZirStatement::Return(
f.fold_expression(statements_buffer, expression),
)],
typed_absy::TypedStatement::Definition(a, e) => {
let a = f.fold_assignee(a);
@ -464,16 +441,21 @@ fn fold_statement<'ast, T: Field>(
};
vec![zir::ZirStatement::Assertion(e, error)]
}
typed_absy::TypedStatement::For(..) => unreachable!(),
typed_absy::TypedStatement::MultipleDefinition(variables, elist) => {
typed_absy::TypedStatement::EmbedCallDefinition(assignee, embed_call) => {
vec![zir::ZirStatement::MultipleDefinition(
variables
.into_iter()
.flat_map(|v| f.fold_assignee(v))
.collect(),
f.fold_expression_list(statements_buffer, elist),
f.fold_assignee(assignee),
zir::ZirExpressionList::EmbedCall(
embed_call.embed,
embed_call.generics,
embed_call
.arguments
.into_iter()
.flat_map(|a| f.fold_expression(statements_buffer, a))
.collect(),
),
)]
}
typed_absy::TypedStatement::For(..) => unreachable!(),
typed_absy::TypedStatement::PushCallLog(..) => vec![],
typed_absy::TypedStatement::PopCallLog => vec![],
};

View file

@ -285,354 +285,240 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
Ok(vec![TypedStatement::For(v, from, to, statements)])
}
TypedStatement::MultipleDefinition(assignees, expression_list) => {
let assignees: Vec<TypedAssignee<'ast, T>> = assignees
.into_iter()
.map(|a| self.fold_assignee(a))
.collect::<Result<_, _>>()?;
let expression_list = self.fold_expression_list(expression_list)?;
TypedStatement::EmbedCallDefinition(assignee, embed_call) => {
let assignee = self.fold_assignee(assignee)?;
let embed_call = self.fold_embed_call(embed_call)?;
let types = Types {
inner: expression_list
.types
.clone()
.inner
.into_iter()
.map(|t| self.fold_type(t))
.collect::<Result<_, _>>()?,
};
fn process_u_from_bits<'ast, T: Field>(
arguments: &[TypedExpression<'ast, T>],
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
assert_eq!(arguments.len(), 1);
let statements = match expression_list.into_inner() {
TypedExpressionListInner::EmbedCall(embed, generics, arguments) => {
let arguments: Vec<_> = arguments
.into_iter()
.map(|a| self.fold_expression(a))
.collect::<Result<_, _>>()?;
let argument = arguments.last().cloned().unwrap();
let argument = argument.into_canonical_constant();
fn process_u_from_bits<'ast, T: Field>(
variables: Vec<TypedAssignee<'ast, T>>,
mut arguments: Vec<TypedExpression<'ast, T>>,
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
assert_eq!(variables.len(), 1);
assert_eq!(arguments.len(), 1);
let argument = arguments.pop().unwrap();
let argument = argument.into_canonical_constant();
match ArrayExpression::try_from(argument)
.unwrap()
.into_inner()
{
ArrayExpressionInner::Value(v) =>
UExpressionInner::Value(
v.into_iter()
.map(|v| match v {
TypedExpressionOrSpread::Expression(
TypedExpression::Boolean(
BooleanExpression::Value(v),
),
) => v,
_ => unreachable!("Should be a constant boolean expression. Spreads are not expected here, as in their presence the argument isn't constant"),
})
.enumerate()
.fold(0, |acc, (i, v)| {
if v {
acc + 2u128.pow(
(bitwidth.to_usize() - i - 1)
.try_into()
.unwrap(),
)
} else {
acc
}
}),
)
.annotate(bitwidth)
.into(),
_ => unreachable!("should be an array value"),
}
}
fn process_u_to_bits<'ast, T: Field>(
variables: Vec<TypedAssignee<'ast, T>>,
arguments: Vec<TypedExpression<'ast, T>>,
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
assert_eq!(variables.len(), 1);
assert_eq!(arguments.len(), 1);
match UExpression::try_from(arguments[0].clone())
.unwrap()
.into_inner()
{
UExpressionInner::Value(v) => {
let mut num = v;
let mut res = vec![];
for i in (0..bitwidth as u32).rev() {
if 2u128.pow(i) <= num {
num -= 2u128.pow(i);
res.push(true);
match ArrayExpression::try_from(argument)
.unwrap()
.into_inner()
{
ArrayExpressionInner::Value(v) =>
UExpressionInner::Value(
v.into_iter()
.map(|v| match v {
TypedExpressionOrSpread::Expression(
TypedExpression::Boolean(
BooleanExpression::Value(v),
),
) => v,
_ => unreachable!("Should be a constant boolean expression. Spreads are not expected here, as in their presence the argument isn't constant"),
})
.enumerate()
.fold(0, |acc, (i, v)| {
if v {
acc + 2u128.pow(
(bitwidth.to_usize() - i - 1)
.try_into()
.unwrap(),
)
} else {
res.push(false);
acc
}
}
assert_eq!(num, 0);
ArrayExpressionInner::Value(
res.into_iter()
.map(|v| BooleanExpression::Value(v).into())
.collect::<Vec<_>>()
.into(),
)
.annotate(Type::Boolean, bitwidth.to_usize() as u32)
.into()
}
_ => unreachable!("should be a uint value"),
}
}
match arguments.iter().all(|a| a.is_constant()) {
true => {
let r: Option<TypedExpression<'ast, T>> = match embed {
FlatEmbed::BitArrayLe => Ok(None), // todo
FlatEmbed::U64FromBits => Ok(Some(process_u_from_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B64,
))),
FlatEmbed::U32FromBits => Ok(Some(process_u_from_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B32,
))),
FlatEmbed::U16FromBits => Ok(Some(process_u_from_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B16,
))),
FlatEmbed::U8FromBits => Ok(Some(process_u_from_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B8,
))),
FlatEmbed::U64ToBits => Ok(Some(process_u_to_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B64,
))),
FlatEmbed::U32ToBits => Ok(Some(process_u_to_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B32,
))),
FlatEmbed::U16ToBits => Ok(Some(process_u_to_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B16,
))),
FlatEmbed::U8ToBits => Ok(Some(process_u_to_bits(
assignees.clone(),
arguments.clone(),
UBitwidth::B8,
))),
FlatEmbed::Unpack => {
assert_eq!(assignees.len(), 1);
assert_eq!(arguments.len(), 1);
assert_eq!(generics.len(), 1);
let bit_width = generics[0];
match FieldElementExpression::<T>::try_from(
arguments[0].clone(),
)
.unwrap()
{
FieldElementExpression::Number(num) => {
let mut acc = num.clone();
let mut res = vec![];
for i in (0..bit_width as usize).rev() {
if T::from(2).pow(i) <= acc {
acc = acc - T::from(2).pow(i);
res.push(true);
} else {
res.push(false);
}
}
if acc != T::zero() {
Err(Error::ValueTooLarge(format!(
"Cannot unpack `{}` to `{}`: value is too large",
num, assignees.first().unwrap().get_type()
)))
} else {
Ok(Some(
ArrayExpressionInner::Value(
res.into_iter()
.map(|v| {
BooleanExpression::Value(v)
.into()
})
.collect::<Vec<_>>()
.into(),
)
.annotate(Type::Boolean, bit_width)
.into(),
))
}
}
_ => unreachable!("should be a field value"),
}
}
#[cfg(feature = "bellman")]
FlatEmbed::Sha256Round => Ok(None),
#[cfg(feature = "ark")]
FlatEmbed::SnarkVerifyBls12377 => Ok(None),
}?;
Ok(match r {
// if the function call returns a constant
Some(expr) => {
let mut assignees = assignees;
match assignees.pop().unwrap() {
TypedAssignee::Identifier(var) => {
self.constants.insert(var.id, expr);
vec![]
}
assignee => {
match self.try_get_constant_mut(&assignee) {
Ok((_, c)) => {
*c = expr;
vec![]
}
Err(v) => match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(
v.clone().into(),
c,
),
TypedStatement::Definition(
assignee, expr,
),
],
None => {
vec![TypedStatement::Definition(
assignee, expr,
)]
}
},
}
}
}
}
None => {
// if the function call does not return a constant, invalidate the cache
// this happpens because we only propagate certain calls here
let mut assignees = assignees;
let assignee = assignees.pop().unwrap();
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::MultipleDefinition(
vec![assignee],
TypedExpressionListInner::EmbedCall(
embed, generics, arguments,
)
.annotate(types),
),
],
None => vec![TypedStatement::MultipleDefinition(
vec![assignee],
TypedExpressionListInner::EmbedCall(
embed, generics, arguments,
)
.annotate(types),
)],
}
}
})
}
false => {
// if the function arguments are not constant, invalidate the cache
// for the return assignees
let def = TypedStatement::MultipleDefinition(
assignees.clone(),
TypedExpressionListInner::EmbedCall(embed, generics, arguments)
.annotate(types),
);
let invalidations = assignees.iter().flat_map(|assignee| {
let v = self
.try_get_constant_mut(assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => {
vec![TypedStatement::Definition(v.clone().into(), c)]
}
None => vec![],
}
});
Ok(invalidations.chain(std::iter::once(def)).collect())
}
}
}
TypedExpressionListInner::FunctionCall(function_call) => {
let generics = function_call
.generics
.into_iter()
.map(|g| g.map(|g| self.fold_uint_expression(g)).transpose())
.collect::<Result<_, _>>()?;
let arguments: Vec<_> = function_call
.arguments
.into_iter()
.map(|a| self.fold_expression(a))
.collect::<Result<_, _>>()?;
// invalidate the cache for the return assignees as this call mutates them
let def = TypedStatement::MultipleDefinition(
assignees.clone(),
TypedExpressionList::function_call(
function_call.function_key,
generics,
arguments,
}),
)
.annotate(types),
);
let invalidations = assignees.iter().flat_map(|assignee| {
let v = self
.try_get_constant_mut(assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => {
vec![TypedStatement::Definition(v.clone().into(), c)]
}
None => vec![],
}
});
Ok(invalidations.chain(std::iter::once(def)).collect())
.annotate(bitwidth)
.into(),
_ => unreachable!("should be an array value"),
}
}?;
}
Ok(statements)
fn process_u_to_bits<'ast, T: Field>(
arguments: &[TypedExpression<'ast, T>],
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
assert_eq!(arguments.len(), 1);
match UExpression::try_from(arguments[0].clone())
.unwrap()
.into_inner()
{
UExpressionInner::Value(v) => {
let mut num = v;
let mut res = vec![];
for i in (0..bitwidth as u32).rev() {
if 2u128.pow(i) <= num {
num -= 2u128.pow(i);
res.push(true);
} else {
res.push(false);
}
}
assert_eq!(num, 0);
ArrayExpressionInner::Value(
res.into_iter()
.map(|v| BooleanExpression::Value(v).into())
.collect::<Vec<_>>()
.into(),
)
.annotate(Type::Boolean, bitwidth.to_usize() as u32)
.into()
}
_ => unreachable!("should be a uint value"),
}
}
match embed_call.arguments.iter().all(|a| a.is_constant()) {
true => {
let r: Option<TypedExpression<'ast, T>> = match embed_call.embed {
FlatEmbed::BitArrayLe => Ok(None), // todo
FlatEmbed::U64FromBits => Ok(Some(process_u_from_bits(
&embed_call.arguments,
UBitwidth::B64,
))),
FlatEmbed::U32FromBits => Ok(Some(process_u_from_bits(
&embed_call.arguments,
UBitwidth::B32,
))),
FlatEmbed::U16FromBits => Ok(Some(process_u_from_bits(
&embed_call.arguments,
UBitwidth::B16,
))),
FlatEmbed::U8FromBits => Ok(Some(process_u_from_bits(
&embed_call.arguments,
UBitwidth::B8,
))),
FlatEmbed::U64ToBits => Ok(Some(process_u_to_bits(
&embed_call.arguments,
UBitwidth::B64,
))),
FlatEmbed::U32ToBits => Ok(Some(process_u_to_bits(
&embed_call.arguments,
UBitwidth::B32,
))),
FlatEmbed::U16ToBits => Ok(Some(process_u_to_bits(
&embed_call.arguments,
UBitwidth::B16,
))),
FlatEmbed::U8ToBits => Ok(Some(process_u_to_bits(
&embed_call.arguments,
UBitwidth::B8,
))),
FlatEmbed::Unpack => {
assert_eq!(embed_call.arguments.len(), 1);
assert_eq!(embed_call.generics.len(), 1);
let bit_width = embed_call.generics[0];
match FieldElementExpression::<T>::try_from(
embed_call.arguments[0].clone(),
)
.unwrap()
{
FieldElementExpression::Number(num) => {
let mut acc = num.clone();
let mut res = vec![];
for i in (0..bit_width as usize).rev() {
if T::from(2).pow(i) <= acc {
acc = acc - T::from(2).pow(i);
res.push(true);
} else {
res.push(false);
}
}
if acc != T::zero() {
Err(Error::ValueTooLarge(format!(
"Cannot unpack `{}` to `{}`: value is too large",
num,
assignee.get_type()
)))
} else {
Ok(Some(
ArrayExpressionInner::Value(
res.into_iter()
.map(|v| BooleanExpression::Value(v).into())
.collect::<Vec<_>>()
.into(),
)
.annotate(Type::Boolean, bit_width)
.into(),
))
}
}
_ => unreachable!("should be a field value"),
}
}
#[cfg(feature = "bellman")]
FlatEmbed::Sha256Round => Ok(None),
#[cfg(feature = "ark")]
FlatEmbed::SnarkVerifyBls12377 => Ok(None),
}?;
Ok(match r {
// if the function call returns a constant
Some(expr) => match assignee {
TypedAssignee::Identifier(var) => {
self.constants.insert(var.id, expr);
vec![]
}
assignee => match self.try_get_constant_mut(&assignee) {
Ok((_, c)) => {
*c = expr;
vec![]
}
Err(v) => match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::Definition(assignee, expr),
],
None => {
vec![TypedStatement::Definition(assignee, expr)]
}
},
},
},
None => {
// if the function call does not return a constant, invalidate the cache
// this happens because we only propagate certain calls here
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::EmbedCallDefinition(assignee, embed_call),
],
None => vec![TypedStatement::EmbedCallDefinition(
assignee, embed_call,
)],
}
}
})
}
false => {
// if the function arguments are not constant, invalidate the cache
// for the return assignees
let def = TypedStatement::EmbedCallDefinition(assignee.clone(), embed_call);
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
Ok(match self.constants.remove(&v.id) {
Some(c) => {
vec![TypedStatement::Definition(v.clone().into(), c), def]
}
None => vec![def],
})
}
}
}
TypedStatement::Assertion(e, ty) => {
let e_str = e.to_string();

View file

@ -4,8 +4,8 @@ use crate::static_analysis::reducer::ConstantDefinitions;
use crate::typed_absy::{
folder::*, ArrayExpression, ArrayExpressionInner, ArrayType, BooleanExpression, CoreIdentifier,
DeclarationConstant, Expr, FieldElementExpression, Identifier, StructExpression,
StructExpressionInner, StructType, TypedProgram, TypedSymbolDeclaration, UBitwidth,
UExpression, UExpressionInner,
StructExpressionInner, StructType, TupleExpression, TupleExpressionInner, TupleType,
TypedProgram, TypedSymbolDeclaration, UBitwidth, UExpression, UExpressionInner,
};
use zokrates_field::Field;
@ -33,6 +33,26 @@ impl<'a, 'ast, T: Field> ConstantsReader<'a, 'ast, T> {
}
impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> {
fn fold_declaration_constant(
&mut self,
c: DeclarationConstant<'ast, T>,
) -> DeclarationConstant<'ast, T> {
match c {
DeclarationConstant::Constant(c) => {
let c = self.fold_canonical_constant_identifier(c);
match self.constants.get(&c).cloned() {
Some(e) => match UExpression::try_from(e).unwrap().into_inner() {
UExpressionInner::Value(v) => DeclarationConstant::Concrete(v as u32),
_ => unreachable!(),
},
None => DeclarationConstant::Constant(c),
}
}
c => fold_declaration_constant(self, c),
}
}
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
@ -124,6 +144,29 @@ impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> {
}
}
fn fold_tuple_expression_inner(
&mut self,
ty: &TupleType<'ast, T>,
e: TupleExpressionInner<'ast, T>,
) -> TupleExpressionInner<'ast, T> {
match e {
TupleExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}) => {
assert_eq!(version, 0);
match self.constants.get(&c).cloned() {
Some(v) => TupleExpression::try_from(v).unwrap().into_inner(),
None => TupleExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}),
}
}
e => fold_tuple_expression_inner(self, ty, e),
}
}
fn fold_struct_expression_inner(
&mut self,
ty: &StructType<'ast, T>,
@ -146,24 +189,4 @@ impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> {
e => fold_struct_expression_inner(self, ty, e),
}
}
fn fold_declaration_constant(
&mut self,
c: DeclarationConstant<'ast, T>,
) -> DeclarationConstant<'ast, T> {
match c {
DeclarationConstant::Constant(c) => {
let c = self.fold_canonical_constant_identifier(c);
match self.constants.get(&c).cloned() {
Some(e) => match UExpression::try_from(e).unwrap().into_inner() {
UExpressionInner::Value(v) => DeclarationConstant::Concrete(v as u32),
_ => unreachable!(),
},
None => DeclarationConstant::Constant(c),
}
}
c => fold_declaration_constant(self, c),
}
}
}

View file

@ -4,9 +4,9 @@ use crate::static_analysis::reducer::{
constants_reader::ConstantsReader, reduce_function, ConstantDefinitions, Error,
};
use crate::typed_absy::{
result_folder::*, types::ConcreteGenericsAssignment, OwnedTypedModuleId, TypedConstant,
TypedConstantSymbol, TypedConstantSymbolDeclaration, TypedModuleId, TypedProgram,
TypedSymbolDeclaration, UExpression,
result_folder::*, types::ConcreteGenericsAssignment, Constant, OwnedTypedModuleId, Typed,
TypedConstant, TypedConstantSymbol, TypedConstantSymbolDeclaration, TypedModuleId,
TypedProgram, TypedSymbolDeclaration, UExpression,
};
use std::collections::{BTreeMap, HashSet};
use zokrates_field::Field;
@ -114,8 +114,8 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantsWriter<'ast, T> {
// wrap this expression in a function
let wrapper = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![c.expression])],
signature: DeclarationSignature::new().outputs(vec![c.ty.clone()]),
statements: vec![TypedStatement::Return(c.expression)],
signature: DeclarationSignature::new().output(c.ty.clone()),
};
let mut inlined_wrapper = reduce_function(
@ -124,27 +124,21 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantsWriter<'ast, T> {
&self.program,
)?;
if let TypedStatement::Return(mut expressions) =
if let TypedStatement::Return(expression) =
inlined_wrapper.statements.pop().unwrap()
{
assert_eq!(expressions.len(), 1);
let constant_expression = expressions.pop().unwrap();
use crate::typed_absy::Constant;
if !constant_expression.is_constant() {
if !expression.is_constant() {
return Err(Error::ConstantReduction(id.id.to_string(), id.module));
};
use crate::typed_absy::Typed;
if crate::typed_absy::types::try_from_g_type::<_, UExpression<'ast, T>>(
c.ty.clone(),
)
.unwrap()
== constant_expression.get_type()
== expression.get_type()
{
// add to the constant map
self.constants
.insert(id.clone(), constant_expression.clone());
self.constants.insert(id.clone(), expression.clone());
// after we reduced a constant, propagate it through the whole program
self.update_program();
@ -152,12 +146,12 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantsWriter<'ast, T> {
Ok(TypedConstantSymbolDeclaration {
id,
symbol: TypedConstantSymbol::Here(TypedConstant {
expression: constant_expression,
expression,
ty: c.ty,
}),
})
} else {
Err(Error::Type(format!("Expression of type `{}` cannot be assigned to constant `{}` of type `{}`", constant_expression.get_type(), id, c.ty)))
Err(Error::Type(format!("Expression of type `{}` cannot be assigned to constant `{}` of type `{}`", expression.get_type(), id, c.ty)))
}
} else {
Err(Error::ConstantReduction(id.id.to_string(), id.module))

View file

@ -30,15 +30,15 @@ use crate::embed::FlatEmbed;
use crate::static_analysis::reducer::Output;
use crate::static_analysis::reducer::ShallowTransformer;
use crate::static_analysis::reducer::Versions;
use crate::typed_absy::types::{ConcreteGenericsAssignment, IntoTypes};
use crate::typed_absy::CoreIdentifier;
use crate::typed_absy::types::{ConcreteGenericsAssignment, IntoType};
use crate::typed_absy::Identifier;
use crate::typed_absy::TypedAssignee;
use crate::typed_absy::{
ConcreteFunctionKey, ConcreteSignature, ConcreteVariable, DeclarationFunctionKey, Expr,
Signature, TypedExpression, TypedFunctionSymbol, TypedFunctionSymbolDeclaration, TypedProgram,
TypedStatement, Types, UExpression, UExpressionInner, Variable,
TypedStatement, UExpression, UExpressionInner, Variable,
};
use crate::typed_absy::{CoreIdentifier, Type};
use zokrates_field::Field;
pub enum InlineError<'ast, T> {
@ -47,13 +47,13 @@ pub enum InlineError<'ast, T> {
FlatEmbed,
Vec<u32>,
Vec<TypedExpression<'ast, T>>,
Types<'ast, T>,
Type<'ast, T>,
),
NonConstant(
DeclarationFunctionKey<'ast, T>,
Vec<Option<UExpression<'ast, T>>>,
Vec<TypedExpression<'ast, T>>,
Types<'ast, T>,
Type<'ast, T>,
),
}
@ -76,7 +76,7 @@ fn get_canonical_function<'ast, T: Field>(
}
type InlineResult<'ast, T> = Result<
Output<(Vec<TypedStatement<'ast, T>>, Vec<TypedExpression<'ast, T>>), Vec<Versions<'ast>>>,
Output<(Vec<TypedStatement<'ast, T>>, TypedExpression<'ast, T>), Vec<Versions<'ast>>>,
InlineError<'ast, T>,
>;
@ -91,8 +91,7 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
use std::convert::TryFrom;
use crate::typed_absy::Typed;
let output_types = output.clone().into_types();
let output_type = output.clone().into_type();
// we try to get concrete values for explicit generics
let generics_values: Vec<Option<u32>> = generics
@ -111,7 +110,7 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
k.clone(),
generics.clone(),
arguments.clone(),
output_types.clone(),
output_type.clone(),
)
})?;
@ -120,7 +119,7 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
let inferred_signature = Signature::new()
.generics(generics.clone())
.inputs(arguments.iter().map(|a| a.get_type()).collect())
.outputs(output_types.clone().inner);
.output(output_type.clone());
// we try to get concrete values for the whole signature. if this fails we should propagate again
let inferred_signature = match ConcreteSignature::try_from(inferred_signature) {
@ -130,7 +129,7 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
k,
generics,
arguments,
output_types,
output_type,
));
}
};
@ -158,7 +157,7 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
e,
e.generics::<T>(&assignment),
arguments.clone(),
output_types,
output_type,
)),
_ => unreachable!(),
}?;
@ -188,51 +187,39 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
assert_eq!(returns.len(), 1);
let returns = match returns.pop().unwrap() {
let return_expression = match returns.pop().unwrap() {
TypedStatement::Return(e) => e,
_ => unreachable!(),
};
let res: Vec<ConcreteVariable<'ast>> = inferred_signature
.outputs
.iter()
.enumerate()
.map(|(i, t)| {
ConcreteVariable::with_id_and_type(
Identifier::from(CoreIdentifier::Call(i)).version(
*versions
.entry(CoreIdentifier::Call(i).clone())
.and_modify(|e| *e += 1) // if it was already declared, we increment
.or_insert(0),
),
t.clone(),
)
})
.collect();
let v: ConcreteVariable<'ast> = ConcreteVariable::with_id_and_type(
Identifier::from(CoreIdentifier::Call(0)).version(
*versions
.entry(CoreIdentifier::Call(0).clone())
.and_modify(|e| *e += 1) // if it was already declared, we increment
.or_insert(0),
),
*inferred_signature.output.clone(),
);
let expressions: Vec<TypedExpression<_>> = res
.iter()
.map(|v| TypedExpression::from(Variable::from(v.clone())))
.collect();
// let expressions: Vec<TypedExpression<_>> =
// vec![TypedExpression::from(Variable::from(v.clone()))];
assert_eq!(res.len(), returns.len());
let expression = TypedExpression::from(Variable::from(v.clone()));
let output_bindings: Vec<TypedStatement<'ast, T>> = res
.into_iter()
.zip(returns)
.map(|(v, a)| TypedStatement::Definition(TypedAssignee::Identifier(v.into()), a))
.collect();
let output_binding =
TypedStatement::Definition(TypedAssignee::Identifier(v.into()), return_expression);
let pop_log = TypedStatement::PopCallLog;
let statements: Vec<_> = std::iter::once(call_log)
.chain(input_bindings)
.chain(statements)
.chain(output_bindings)
.chain(std::iter::once(output_binding))
.chain(std::iter::once(pop_log))
.collect();
Ok(incomplete_data
.map(|d| Output::Incomplete((statements.clone(), expressions.clone()), d))
.unwrap_or_else(|| Output::Complete((statements, expressions))))
.map(|d| Output::Incomplete((statements.clone(), expression.clone()), d))
.unwrap_or_else(|| Output::Complete((statements, expression))))
}

View file

@ -20,16 +20,15 @@ use self::inline::{inline_call, InlineError};
use crate::typed_absy::result_folder::*;
use crate::typed_absy::types::ConcreteGenericsAssignment;
use crate::typed_absy::types::GGenericsAssignment;
use crate::typed_absy::CanonicalConstantIdentifier;
use crate::typed_absy::Folder;
use crate::typed_absy::{CanonicalConstantIdentifier, EmbedCall, Variable};
use std::collections::HashMap;
use crate::typed_absy::{
ArrayExpressionInner, ArrayType, BlockExpression, CoreIdentifier, Expr, FunctionCall,
FunctionCallExpression, FunctionCallOrExpression, Id, Identifier, OwnedTypedModuleId,
TypedExpression, TypedExpressionList, TypedExpressionListInner, TypedFunction,
TypedFunctionSymbol, TypedFunctionSymbolDeclaration, TypedModule, TypedProgram, TypedStatement,
UExpression, UExpressionInner, Variable,
TypedExpression, TypedFunction, TypedFunctionSymbol, TypedFunctionSymbolDeclaration,
TypedModule, TypedProgram, TypedStatement, UExpression, UExpressionInner,
};
use zokrates_field::Field;
@ -240,19 +239,19 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
);
match res {
Ok(Output::Complete((statements, mut expressions))) => {
Ok(Output::Complete((statements, expression))) => {
self.complete &= true;
self.statement_buffer.extend(statements);
Ok(FunctionCallOrExpression::Expression(
E::from(expressions.pop().unwrap()).into_inner(),
E::from(expression).into_inner(),
))
}
Ok(Output::Incomplete((statements, expressions), delta_for_loop_versions)) => {
Ok(Output::Incomplete((statements, expression), delta_for_loop_versions)) => {
self.complete = false;
self.statement_buffer.extend(statements);
self.for_loop_versions_after.extend(delta_for_loop_versions);
Ok(FunctionCallOrExpression::Expression(
E::from(expressions[0].clone()).into_inner(),
E::from(expression.clone()).into_inner(),
))
}
Err(InlineError::Generic(decl, conc)) => Err(Error::Incompatible(format!(
@ -266,7 +265,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
key, generics, arguments,
)))
}
Err(InlineError::Flat(embed, generics, arguments, output_types)) => {
Err(InlineError::Flat(embed, generics, arguments, output_type)) => {
let identifier = Identifier::from(CoreIdentifier::Call(0)).version(
*self
.versions
@ -274,18 +273,14 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
.and_modify(|e| *e += 1) // if it was already declared, we increment
.or_insert(0),
);
let var = Variable::with_id_and_type(
identifier.clone(),
output_types.clone().inner.pop().unwrap(),
);
let var = Variable::with_id_and_type(identifier.clone(), output_type);
let v = vec![var.clone().into()];
let v = var.clone().into();
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
.push(TypedStatement::EmbedCallDefinition(
v,
TypedExpressionListInner::EmbedCall(embed, generics, arguments)
.annotate(output_types),
EmbedCall::new(embed, generics, arguments),
));
Ok(FunctionCallOrExpression::Expression(E::identifier(
identifier,
@ -329,84 +324,6 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
s: TypedStatement<'ast, T>,
) -> Result<Vec<TypedStatement<'ast, T>>, Self::Error> {
let res = match s {
TypedStatement::MultipleDefinition(
v,
TypedExpressionList {
inner: TypedExpressionListInner::FunctionCall(function_call),
types,
},
) => {
let generics = function_call
.generics
.into_iter()
.map(|g| g.map(|g| self.fold_uint_expression(g)).transpose())
.collect::<Result<_, _>>()?;
let arguments = function_call
.arguments
.into_iter()
.map(|a| self.fold_expression(a))
.collect::<Result<_, _>>()?;
match inline_call::<_, TypedExpressionList<'ast, T>>(
function_call.function_key,
generics,
arguments,
&types,
self.program,
self.versions,
) {
Ok(Output::Complete((statements, expressions))) => {
assert_eq!(v.len(), expressions.len());
self.complete &= true;
Ok(statements
.into_iter()
.chain(
v.into_iter()
.zip(expressions)
.map(|(v, e)| TypedStatement::Definition(v, e)),
)
.collect())
}
Ok(Output::Incomplete((statements, expressions), delta_for_loop_versions)) => {
assert_eq!(v.len(), expressions.len());
self.complete = false;
self.for_loop_versions_after.extend(delta_for_loop_versions);
Ok(statements
.into_iter()
.chain(
v.into_iter()
.zip(expressions)
.map(|(v, e)| TypedStatement::Definition(v, e)),
)
.collect())
}
Err(InlineError::Generic(decl, conc)) => Err(Error::Incompatible(format!(
"Call site `{}` incompatible with declaration `{}`",
conc, decl
))),
Err(InlineError::NonConstant(key, generics, arguments, output_types)) => {
self.complete = false;
Ok(vec![TypedStatement::MultipleDefinition(
v,
TypedExpressionList::function_call(key, generics, arguments)
.annotate(output_types),
)])
}
Err(InlineError::Flat(embed, generics, arguments, output_types)) => {
Ok(vec![TypedStatement::MultipleDefinition(
v,
TypedExpressionListInner::EmbedCall(embed, generics, arguments)
.annotate(output_types),
)])
}
}
}
TypedStatement::For(v, from, to, statements) => {
let versions_before = self.for_loop_versions.pop().unwrap();
@ -640,13 +557,13 @@ fn compute_hash<T: Field>(f: &TypedFunction<T>) -> u64 {
#[cfg(test)]
mod tests {
use super::*;
use crate::typed_absy::types::DeclarationConstant;
use crate::typed_absy::types::DeclarationSignature;
use crate::typed_absy::types::{DeclarationConstant, GTupleType};
use crate::typed_absy::{
ArrayExpression, ArrayExpressionInner, DeclarationFunctionKey, DeclarationType,
DeclarationVariable, FieldElementExpression, GenericIdentifier, Identifier,
OwnedTypedModuleId, Select, Type, TypedExpression, TypedExpressionList,
TypedExpressionOrSpread, Types, UBitwidth, UExpressionInner, Variable,
OwnedTypedModuleId, Select, TupleExpressionInner, TupleType, Type, TypedExpression,
TypedExpressionOrSpread, UBitwidth, UExpressionInner, Variable,
};
use zokrates_field::Bn128Field;
@ -683,12 +600,12 @@ mod tests {
let foo: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![DeclarationVariable::field_element("a").into()],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
FieldElementExpression::Identifier("a".into()).into(),
])],
)],
signature: DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let main: TypedFunction<Bn128Field> = TypedFunction {
@ -708,18 +625,18 @@ mod tests {
Variable::field_element("a").into(),
FieldElementExpression::Identifier("a".into()).into(),
),
TypedStatement::MultipleDefinition(
vec![Variable::field_element("a").into()],
TypedExpressionList::function_call(
TypedStatement::Definition(
Variable::field_element("a").into(),
FieldElementExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
vec![],
vec![FieldElementExpression::Identifier("a".into()).into()],
)
.annotate(Types::new(vec![Type::FieldElement])),
.into(),
),
TypedStatement::Definition(
Variable::uint("n", UBitwidth::B32).into(),
@ -727,11 +644,11 @@ mod tests {
.annotate(UBitwidth::B32)
.into(),
),
TypedStatement::Return(vec![FieldElementExpression::Identifier("a".into()).into()]),
TypedStatement::Return(FieldElementExpression::Identifier("a".into()).into()),
],
signature: DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let p = TypedProgram {
@ -744,7 +661,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "foo").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(foo),
)
@ -753,7 +670,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(main),
)
@ -778,7 +695,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "foo").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
GGenericsAssignment::default(),
),
@ -799,14 +716,13 @@ mod tests {
)
.into(),
),
TypedStatement::Return(vec![FieldElementExpression::Identifier(
Identifier::from("a").version(2),
)
.into()]),
TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from("a").version(2)).into(),
),
],
signature: DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let expected: TypedProgram<Bn128Field> = TypedProgram {
@ -818,7 +734,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(expected_main),
)
@ -865,10 +781,10 @@ mod tests {
DeclarationType::FieldElement,
DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)),
))])
.outputs(vec![DeclarationType::array((
.output(DeclarationType::array((
DeclarationType::FieldElement,
DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)),
))]);
)));
let foo: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![DeclarationVariable::array(
@ -877,11 +793,11 @@ mod tests {
GenericIdentifier::with_name("K").with_index(0),
)
.into()],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
ArrayExpressionInner::Identifier("a".into())
.annotate(Type::FieldElement, 1u32)
.into(),
])],
)],
signature: foo_signature.clone(),
};
@ -906,9 +822,9 @@ mod tests {
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::MultipleDefinition(
vec![Variable::array("b", Type::FieldElement, 1u32).into()],
TypedExpressionList::function_call(
TypedStatement::Definition(
Variable::array("b", Type::FieldElement, 1u32).into(),
ArrayExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
vec![None],
@ -916,7 +832,8 @@ mod tests {
.annotate(Type::FieldElement, 1u32)
.into()],
)
.annotate(Types::new(vec![Type::array((Type::FieldElement, 1u32))])),
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::Definition(
Variable::uint("n", UBitwidth::B32).into(),
@ -924,17 +841,19 @@ mod tests {
.annotate(UBitwidth::B32)
.into(),
),
TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier("b".into())
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into()]),
TypedStatement::Return(
(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier("b".into())
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into(),
),
],
signature: DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let p = TypedProgram {
@ -953,7 +872,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(main),
)
@ -1015,17 +934,19 @@ mod tests {
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from("b").version(1))
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into()]),
TypedStatement::Return(
(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from("b").version(1))
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into(),
),
],
signature: DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let expected = TypedProgram {
@ -1037,7 +958,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(expected_main),
)
@ -1084,10 +1005,10 @@ mod tests {
DeclarationType::FieldElement,
DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)),
))])
.outputs(vec![DeclarationType::array((
.output(DeclarationType::array((
DeclarationType::FieldElement,
DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)),
))]);
)));
let foo: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![DeclarationVariable::array(
@ -1096,11 +1017,11 @@ mod tests {
GenericIdentifier::with_name("K").with_index(0),
)
.into()],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
ArrayExpressionInner::Identifier("a".into())
.annotate(Type::FieldElement, 1u32)
.into(),
])],
)],
signature: foo_signature.clone(),
};
@ -1134,9 +1055,9 @@ mod tests {
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::MultipleDefinition(
vec![Variable::array("b", Type::FieldElement, 1u32).into()],
TypedExpressionList::function_call(
TypedStatement::Definition(
Variable::array("b", Type::FieldElement, 1u32).into(),
ArrayExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
vec![None],
@ -1144,7 +1065,8 @@ mod tests {
.annotate(Type::FieldElement, 1u32)
.into()],
)
.annotate(Types::new(vec![Type::array((Type::FieldElement, 1u32))])),
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::Definition(
Variable::uint("n", UBitwidth::B32).into(),
@ -1152,17 +1074,19 @@ mod tests {
.annotate(UBitwidth::B32)
.into(),
),
TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier("b".into())
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into()]),
TypedStatement::Return(
(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier("b".into())
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into(),
),
],
signature: DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let p = TypedProgram {
@ -1181,7 +1105,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(main),
)
@ -1243,17 +1167,19 @@ mod tests {
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::Return(vec![(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from("b").version(1))
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into()]),
TypedStatement::Return(
(FieldElementExpression::Identifier("a".into())
+ FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from("b").version(1))
.annotate(Type::FieldElement, 1u32),
0u32,
))
.into(),
),
],
signature: DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let expected = TypedProgram {
@ -1265,7 +1191,7 @@ mod tests {
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
TypedFunctionSymbol::Here(expected_main),
)
@ -1312,10 +1238,10 @@ mod tests {
DeclarationType::FieldElement,
DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)),
))])
.outputs(vec![DeclarationType::array((
.output(DeclarationType::array((
DeclarationType::FieldElement,
DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)),
))])
)))
.generics(vec![Some(
GenericIdentifier::with_name("K").with_index(0).into(),
)]);
@ -1372,12 +1298,14 @@ mod tests {
)
.into(),
),
TypedStatement::Return(vec![ArrayExpressionInner::Identifier("ret".into())
.annotate(
Type::FieldElement,
UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32),
)
.into()]),
TypedStatement::Return(
ArrayExpressionInner::Identifier("ret".into())
.annotate(
Type::FieldElement,
UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32),
)
.into(),
),
],
signature: foo_signature.clone(),
};
@ -1391,23 +1319,23 @@ mod tests {
DeclarationConstant::Generic(GenericIdentifier::with_name("K").with_index(0)),
)
.into()],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
ArrayExpressionInner::Identifier("a".into())
.annotate(
Type::FieldElement,
UExpressionInner::Identifier("K".into()).annotate(UBitwidth::B32),
)
.into(),
])],
)],
signature: bar_signature.clone(),
};
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![
TypedStatement::MultipleDefinition(
vec![Variable::array("b", Type::FieldElement, 1u32).into()],
TypedExpressionList::function_call(
TypedStatement::Definition(
Variable::array("b", Type::FieldElement, 1u32).into(),
ArrayExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
vec![None],
@ -1417,9 +1345,14 @@ mod tests {
.annotate(Type::FieldElement, 1u32)
.into()],
)
.annotate(Types::new(vec![Type::array((Type::FieldElement, 1u32))])),
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::Return(
TupleExpressionInner::Value(vec![])
.annotate(TupleType::new(vec![]))
.into(),
),
TypedStatement::Return(vec![]),
],
signature: DeclarationSignature::new(),
};
@ -1479,7 +1412,11 @@ mod tests {
),
TypedStatement::PopCallLog,
TypedStatement::PopCallLog,
TypedStatement::Return(vec![]),
TypedStatement::Return(
TupleExpressionInner::Value(vec![])
.annotate(TupleType::new(vec![]))
.into(),
),
],
signature: DeclarationSignature::new(),
};
@ -1525,10 +1462,10 @@ mod tests {
DeclarationType::FieldElement,
GenericIdentifier::with_name("K").with_index(0),
))])
.outputs(vec![DeclarationType::array((
.output(DeclarationType::array((
DeclarationType::FieldElement,
GenericIdentifier::with_name("K").with_index(0),
))]);
)));
let foo: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![DeclarationVariable::array(
@ -1537,20 +1474,20 @@ mod tests {
GenericIdentifier::with_name("K").with_index(0),
)
.into()],
statements: vec![TypedStatement::Return(vec![
statements: vec![TypedStatement::Return(
ArrayExpressionInner::Identifier("a".into())
.annotate(Type::FieldElement, 1u32)
.into(),
])],
)],
signature: foo_signature.clone(),
};
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![
TypedStatement::MultipleDefinition(
vec![Variable::array("b", Type::FieldElement, 1u32).into()],
TypedExpressionList::function_call(
TypedStatement::Definition(
Variable::array("b", Type::FieldElement, 1u32).into(),
ArrayExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
vec![None],
@ -1558,11 +1495,18 @@ mod tests {
.annotate(Type::FieldElement, 0u32)
.into()],
)
.annotate(Types::new(vec![Type::array((Type::FieldElement, 1u32))])),
.annotate(Type::FieldElement, 1u32)
.into(),
),
TypedStatement::Return(
TupleExpressionInner::Value(vec![])
.annotate(TupleType::new(vec![]))
.into(),
),
TypedStatement::Return(vec![]),
],
signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
signature: DeclarationSignature::new()
.inputs(vec![])
.output(DeclarationType::Tuple(GTupleType::new(vec![]))),
};
let p = TypedProgram {
@ -1579,7 +1523,9 @@ mod tests {
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
DeclarationSignature::new()
.inputs(vec![])
.output(DeclarationType::Tuple(GTupleType::new(vec![]))),
),
TypedFunctionSymbol::Here(main),
)

View file

@ -141,20 +141,16 @@ impl<'ast, 'a, T: Field> Folder<'ast, T> for ShallowTransformer<'ast, 'a> {
vec![TypedStatement::Definition(a, e)]
}
TypedStatement::MultipleDefinition(assignees, exprs) => {
let exprs = self.fold_expression_list(exprs);
let assignees = assignees
.into_iter()
.map(|a| match a {
TypedAssignee::Identifier(v) => {
let v = self.issue_next_ssa_variable(v);
TypedAssignee::Identifier(self.fold_variable(v))
}
a => fold_assignee(self, a),
})
.collect();
vec![TypedStatement::MultipleDefinition(assignees, exprs)]
TypedStatement::EmbedCallDefinition(assignee, embed_call) => {
let assignee = match assignee {
TypedAssignee::Identifier(v) => {
let v = self.issue_next_ssa_variable(v);
TypedAssignee::Identifier(self.fold_variable(v))
}
a => fold_assignee(self, a),
};
let embed_call = self.fold_embed_call(embed_call);
vec![TypedStatement::EmbedCallDefinition(assignee, embed_call)]
}
TypedStatement::For(v, from, to, stats) => {
let from = self.fold_uint_expression(from);
@ -338,8 +334,6 @@ mod tests {
#[test]
fn incremental_multiple_definition() {
use crate::typed_absy::types::Type;
// field a
// a = 2
// a = foo(a)
@ -370,28 +364,28 @@ mod tests {
)]
);
let s: TypedStatement<Bn128Field> = TypedStatement::MultipleDefinition(
vec![Variable::field_element("a").into()],
TypedExpressionList::function_call(
let s: TypedStatement<Bn128Field> = TypedStatement::Definition(
Variable::field_element("a").into(),
FieldElementExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
),
vec![],
vec![FieldElementExpression::Identifier("a".into()).into()],
)
.annotate(Types::new(vec![Type::FieldElement])),
.into(),
);
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::MultipleDefinition(
vec![Variable::field_element(Identifier::from("a").version(1)).into()],
TypedExpressionList::function_call(
vec![TypedStatement::Definition(
Variable::field_element(Identifier::from("a").version(1)).into(),
FieldElementExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement])
.output(DeclarationType::FieldElement)
),
vec![],
vec![
@ -399,7 +393,7 @@ mod tests {
.into()
]
)
.annotate(Types::new(vec![Type::FieldElement]))
.into()
)]
);
}
@ -659,16 +653,14 @@ mod tests {
Variable::field_element("a").into(),
FieldElementExpression::Identifier("a".into()).into(),
),
TypedStatement::Return(vec![
FieldElementExpression::Identifier("a".into()).into()
]),
TypedStatement::Return(FieldElementExpression::Identifier("a".into()).into()),
],
signature: DeclarationSignature::new()
.generics(vec![Some(
GenericIdentifier::with_name("K").with_index(0).into(),
)])
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let mut versions = Versions::default();
@ -738,17 +730,16 @@ mod tests {
Variable::field_element(Identifier::from("a").version(5)).into(),
FieldElementExpression::Identifier(Identifier::from("a").version(4)).into(),
),
TypedStatement::Return(vec![FieldElementExpression::Identifier(
Identifier::from("a").version(5),
)
.into()]),
TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from("a").version(5)).into(),
),
],
signature: DeclarationSignature::new()
.generics(vec![Some(
GenericIdentifier::with_name("K").with_index(0).into(),
)])
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
assert_eq!(
@ -819,16 +810,16 @@ mod tests {
Variable::field_element("a").into(),
FieldElementExpression::Identifier("a".into()).into(),
),
TypedStatement::MultipleDefinition(
vec![Variable::field_element("a").into()],
TypedExpressionList::function_call(
TypedStatement::Definition(
Variable::field_element("a").into(),
FieldElementExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo"),
vec![Some(
UExpressionInner::Identifier("n".into()).annotate(UBitwidth::B32),
)],
vec![FieldElementExpression::Identifier("a".into()).into()],
)
.annotate(Types::new(vec![Type::FieldElement])),
.into(),
),
TypedStatement::Definition(
Variable::uint("n", UBitwidth::B32).into(),
@ -849,16 +840,14 @@ mod tests {
))
.into(),
),
TypedStatement::Return(vec![
FieldElementExpression::Identifier("a".into()).into()
]),
TypedStatement::Return(FieldElementExpression::Identifier("a".into()).into()),
],
signature: DeclarationSignature::new()
.generics(vec![Some(
GenericIdentifier::with_name("K").with_index(0).into(),
)])
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
let mut versions = Versions::default();
@ -894,9 +883,9 @@ mod tests {
Variable::field_element(Identifier::from("a").version(1)).into(),
FieldElementExpression::Identifier("a".into()).into(),
),
TypedStatement::MultipleDefinition(
vec![Variable::field_element(Identifier::from("a").version(2)).into()],
TypedExpressionList::function_call(
TypedStatement::Definition(
Variable::field_element(Identifier::from("a").version(2)).into(),
FieldElementExpression::function_call(
DeclarationFunctionKey::with_location("main", "foo"),
vec![Some(
UExpressionInner::Identifier(Identifier::from("n").version(1))
@ -907,7 +896,7 @@ mod tests {
)
.into()],
)
.annotate(Types::new(vec![Type::FieldElement])),
.into(),
),
TypedStatement::Definition(
Variable::uint(Identifier::from("n").version(2), UBitwidth::B32).into(),
@ -931,17 +920,16 @@ mod tests {
))
.into(),
),
TypedStatement::Return(vec![FieldElementExpression::Identifier(
Identifier::from("a").version(3),
)
.into()]),
TypedStatement::Return(
FieldElementExpression::Identifier(Identifier::from("a").version(3)).into(),
),
],
signature: DeclarationSignature::new()
.generics(vec![Some(
GenericIdentifier::with_name("K").with_index(0).into(),
)])
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
.output(DeclarationType::FieldElement),
};
assert_eq!(

View file

@ -83,7 +83,7 @@ impl<'ast, T: Field> Folder<'ast, T> for StructConcretizer<'ast, T> {
let size = ty.size.map_concrete(&self.generics).unwrap();
DeclarationArrayType {
size: DeclarationConstant::Concrete(size),
size: box DeclarationConstant::Concrete(size),
ty: box self.fold_declaration_type(*ty.ty),
}
}

View file

@ -45,7 +45,7 @@ impl<'ast> VariableWriteRemover {
let tail = indices;
match head {
Access::Select(head) => {
Access::Select(box head) => {
statements.insert(TypedStatement::Assertion(
BooleanExpression::UintLt(box head.clone(), box size.into()),
RuntimeError::SelectRangeCheck,
@ -409,7 +409,7 @@ impl<'ast> VariableWriteRemover {
#[derive(Clone, Debug)]
enum Access<'ast, T: Field> {
Select(UExpression<'ast, T>),
Select(Box<UExpression<'ast, T>>),
Member(MemberId),
Element(u32),
}
@ -420,7 +420,7 @@ fn linear<T: Field>(a: TypedAssignee<T>) -> (Variable<T>, Vec<Access<T>>) {
TypedAssignee::Identifier(v) => (v, vec![]),
TypedAssignee::Select(box array, box index) => {
let (v, mut indices) = linear(array);
indices.push(Access::Select(index));
indices.push(Access::Select(box index));
(v, indices)
}
TypedAssignee::Member(box s, m) => {
@ -473,7 +473,7 @@ impl<'ast, T: Field> Folder<'ast, T> for VariableWriteRemover {
.into(),
Type::Array(array_type) => {
ArrayExpressionInner::Identifier(variable.id.clone())
.annotate(*array_type.ty, array_type.size)
.annotate(*array_type.ty, *array_type.size)
.into()
}
Type::Struct(members) => {
@ -493,7 +493,9 @@ impl<'ast, T: Field> Folder<'ast, T> for VariableWriteRemover {
let indices = indices
.into_iter()
.map(|a| match a {
Access::Select(i) => Access::Select(self.fold_uint_expression(i)),
Access::Select(box i) => {
Access::Select(box self.fold_uint_expression(i))
}
a => a,
})
.collect();

View file

@ -14,7 +14,7 @@ pub type AbiOutput = ConcreteType;
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct Abi {
pub inputs: Vec<AbiInput>,
pub outputs: Vec<AbiOutput>,
pub output: AbiOutput,
}
impl Abi {
@ -22,7 +22,7 @@ impl Abi {
ConcreteSignature {
generics: vec![],
inputs: self.inputs.iter().map(|i| i.ty.clone()).collect(),
outputs: self.outputs.clone(),
output: box self.output.clone(),
}
}
}
@ -31,7 +31,8 @@ impl Abi {
mod tests {
use super::*;
use crate::typed_absy::types::{
ConcreteArrayType, ConcreteFunctionKey, ConcreteStructMember, ConcreteStructType, UBitwidth,
ConcreteArrayType, ConcreteFunctionKey, ConcreteStructMember, ConcreteStructType,
GTupleType, UBitwidth,
};
use crate::typed_absy::{
parameter::DeclarationParameter, variable::DeclarationVariable, ConcreteTupleType,
@ -59,7 +60,7 @@ mod tests {
statements: vec![],
signature: ConcreteSignature::new()
.inputs(vec![ConcreteType::FieldElement, ConcreteType::Boolean])
.outputs(vec![ConcreteType::FieldElement])
.output(ConcreteType::FieldElement)
.into(),
}),
)
@ -87,7 +88,7 @@ mod tests {
ty: ConcreteType::Boolean,
},
],
outputs: vec![ConcreteType::FieldElement],
output: ConcreteType::FieldElement,
};
assert_eq!(expected_abi, abi);
@ -97,11 +98,14 @@ mod tests {
fn serialize_empty() {
let abi: Abi = Abi {
inputs: vec![],
outputs: vec![],
output: ConcreteType::Tuple(GTupleType::new(vec![])),
};
let json = serde_json::to_string(&abi).unwrap();
assert_eq!(&json, r#"{"inputs":[],"outputs":[]}"#);
assert_eq!(
&json,
r#"{"inputs":[],"output":{"type":"tuple","components":{"elements":[]}}}"#
);
let de_abi: Abi = serde_json::from_str(json.as_ref()).unwrap();
assert_eq!(de_abi, abi);
}
@ -113,7 +117,7 @@ mod tests {
let abi: Abi = Abi {
inputs: vec![],
outputs: vec![ConcreteType::Int],
output: ConcreteType::Int,
};
let _ = serde_json::to_string_pretty(&abi).unwrap();
@ -134,7 +138,7 @@ mod tests {
ty: ConcreteType::FieldElement,
},
],
outputs: vec![ConcreteType::FieldElement],
output: ConcreteType::FieldElement,
};
let json = serde_json::to_string_pretty(&abi).unwrap();
@ -153,11 +157,9 @@ mod tests {
"type": "field"
}
],
"outputs": [
{
"type": "field"
}
]
"output": {
"type": "field"
}
}"#
);
@ -185,7 +187,7 @@ mod tests {
ty: ConcreteType::Uint(UBitwidth::B32),
},
],
outputs: vec![],
output: ConcreteType::Tuple(GTupleType::new(vec![])),
};
let json = serde_json::to_string_pretty(&abi).unwrap();
@ -209,7 +211,12 @@ mod tests {
"type": "u32"
}
],
"outputs": []
"output": {
"type": "tuple",
"components": {
"elements": []
}
}
}"#
);
@ -236,7 +243,7 @@ mod tests {
)],
)),
}],
outputs: vec![ConcreteType::Struct(ConcreteStructType::new(
output: ConcreteType::Struct(ConcreteStructType::new(
"".into(),
"Foo".into(),
vec![],
@ -244,7 +251,7 @@ mod tests {
ConcreteStructMember::new(String::from("a"), ConcreteType::FieldElement),
ConcreteStructMember::new(String::from("b"), ConcreteType::Boolean),
],
))],
)),
};
let json = serde_json::to_string_pretty(&abi).unwrap();
@ -274,25 +281,23 @@ mod tests {
}
}
],
"outputs": [
{
"type": "struct",
"components": {
"name": "Foo",
"generics": [],
"members": [
{
"name": "a",
"type": "field"
},
{
"name": "b",
"type": "bool"
}
]
}
"output": {
"type": "struct",
"components": {
"name": "Foo",
"generics": [],
"members": [
{
"name": "a",
"type": "field"
},
{
"name": "b",
"type": "bool"
}
]
}
]
}
}"#
);
@ -330,7 +335,7 @@ mod tests {
)],
)),
}],
outputs: vec![],
output: ConcreteType::Tuple(GTupleType::new(vec![])),
};
let json = serde_json::to_string_pretty(&abi).unwrap();
@ -368,7 +373,12 @@ mod tests {
}
}
],
"outputs": []
"output": {
"type": "tuple",
"components": {
"elements": []
}
}
}"#
);
@ -398,7 +408,7 @@ mod tests {
2u32,
)),
}],
outputs: vec![ConcreteType::Boolean],
output: ConcreteType::Boolean,
};
let json = serde_json::to_string_pretty(&abi).unwrap();
@ -430,11 +440,9 @@ mod tests {
}
}
],
"outputs": [
{
"type": "bool"
}
]
"output": {
"type": "bool"
}
}"#
);
@ -453,7 +461,7 @@ mod tests {
2u32,
)),
}],
outputs: vec![ConcreteType::FieldElement],
output: ConcreteType::FieldElement,
};
let json = serde_json::to_string_pretty(&abi).unwrap();
@ -475,11 +483,9 @@ mod tests {
}
}
],
"outputs": [
{
"type": "field"
}
]
"output": {
"type": "field"
}
}"#
);
@ -498,9 +504,7 @@ mod tests {
ConcreteType::Boolean,
])),
}],
outputs: vec![ConcreteType::Tuple(ConcreteTupleType::new(vec![
ConcreteType::FieldElement,
]))],
output: ConcreteType::Tuple(ConcreteTupleType::new(vec![ConcreteType::FieldElement])),
};
let json = serde_json::to_string_pretty(&abi).unwrap();
@ -524,18 +528,16 @@ mod tests {
}
}
],
"outputs": [
{
"type": "tuple",
"components": {
"elements": [
{
"type": "field"
}
]
}
"output": {
"type": "tuple",
"components": {
"elements": [
{
"type": "field"
}
]
}
]
}
}"#
);

View file

@ -166,14 +166,10 @@ pub trait Folder<'ast, T: Field>: Sized {
}
}
fn fold_types(&mut self, tys: Types<'ast, T>) -> Types<'ast, T> {
fold_types(self, tys)
}
fn fold_array_type(&mut self, t: ArrayType<'ast, T>) -> ArrayType<'ast, T> {
ArrayType {
ty: box self.fold_type(*t.ty),
size: self.fold_uint_expression(t.size),
size: box self.fold_uint_expression(*t.size),
}
}
@ -208,6 +204,7 @@ pub trait Folder<'ast, T: Field>: Sized {
match t {
Array(array_type) => Array(self.fold_declaration_array_type(array_type)),
Struct(struct_type) => Struct(self.fold_declaration_struct_type(struct_type)),
Tuple(tuple_type) => Tuple(self.fold_declaration_tuple_type(tuple_type)),
t => t,
}
}
@ -218,7 +215,7 @@ pub trait Folder<'ast, T: Field>: Sized {
) -> DeclarationArrayType<'ast, T> {
DeclarationArrayType {
ty: box self.fold_declaration_type(*t.ty),
size: self.fold_declaration_constant(t.size),
size: box self.fold_declaration_constant(*t.size),
}
}
@ -265,6 +262,10 @@ pub trait Folder<'ast, T: Field>: Sized {
fold_statement(self, s)
}
fn fold_embed_call(&mut self, e: EmbedCall<'ast, T>) -> EmbedCall<'ast, T> {
fold_embed_call(self, e)
}
fn fold_expression_or_spread(
&mut self,
e: TypedExpressionOrSpread<'ast, T>,
@ -300,15 +301,7 @@ pub trait Folder<'ast, T: Field>: Sized {
}
fn fold_expression(&mut self, e: TypedExpression<'ast, T>) -> TypedExpression<'ast, T> {
match e {
TypedExpression::FieldElement(e) => self.fold_field_expression(e).into(),
TypedExpression::Boolean(e) => self.fold_boolean_expression(e).into(),
TypedExpression::Uint(e) => self.fold_uint_expression(e).into(),
TypedExpression::Array(e) => self.fold_array_expression(e).into(),
TypedExpression::Tuple(e) => self.fold_tuple_expression(e).into(),
TypedExpression::Struct(e) => self.fold_struct_expression(e).into(),
TypedExpression::Int(e) => self.fold_int_expression(e).into(),
}
fold_expression(self, e)
}
fn fold_block_expression<E: Fold<'ast, T>>(
@ -394,21 +387,6 @@ pub trait Folder<'ast, T: Field>: Sized {
fold_tuple_expression(self, e)
}
fn fold_expression_list(
&mut self,
es: TypedExpressionList<'ast, T>,
) -> TypedExpressionList<'ast, T> {
fold_expression_list(self, es)
}
fn fold_expression_list_inner(
&mut self,
tys: Types<'ast, T>,
es: TypedExpressionListInner<'ast, T>,
) -> TypedExpressionListInner<'ast, T> {
fold_expression_list_inner(self, tys, es)
}
fn fold_int_expression(&mut self, e: IntExpression<'ast, T>) -> IntExpression<'ast, T> {
fold_int_expression(self, e)
}
@ -419,12 +397,14 @@ pub trait Folder<'ast, T: Field>: Sized {
) -> FieldElementExpression<'ast, T> {
fold_field_expression(self, e)
}
fn fold_boolean_expression(
&mut self,
e: BooleanExpression<'ast, T>,
) -> BooleanExpression<'ast, T> {
fold_boolean_expression(self, e)
}
fn fold_uint_expression(&mut self, e: UExpression<'ast, T>) -> UExpression<'ast, T> {
fold_uint_expression(self, e)
}
@ -514,12 +494,7 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
s: TypedStatement<'ast, T>,
) -> Vec<TypedStatement<'ast, T>> {
let res = match s {
TypedStatement::Return(expressions) => TypedStatement::Return(
expressions
.into_iter()
.map(|e| f.fold_expression(e))
.collect(),
),
TypedStatement::Return(e) => TypedStatement::Return(f.fold_expression(e)),
TypedStatement::Definition(a, e) => {
TypedStatement::Definition(f.fold_assignee(a), f.fold_expression(e))
}
@ -536,15 +511,46 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
.flat_map(|s| f.fold_statement(s))
.collect(),
),
TypedStatement::MultipleDefinition(assignees, elist) => TypedStatement::MultipleDefinition(
assignees.into_iter().map(|a| f.fold_assignee(a)).collect(),
f.fold_expression_list(elist),
),
TypedStatement::EmbedCallDefinition(assignee, embed_call) => {
TypedStatement::EmbedCallDefinition(
f.fold_assignee(assignee),
f.fold_embed_call(embed_call),
)
}
s => s,
};
vec![res]
}
pub fn fold_embed_call<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
e: EmbedCall<'ast, T>,
) -> EmbedCall<'ast, T> {
EmbedCall {
arguments: e
.arguments
.into_iter()
.map(|s| f.fold_expression(s))
.collect(),
..e
}
}
pub fn fold_expression<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
e: TypedExpression<'ast, T>,
) -> TypedExpression<'ast, T> {
match e {
TypedExpression::FieldElement(e) => f.fold_field_expression(e).into(),
TypedExpression::Boolean(e) => f.fold_boolean_expression(e).into(),
TypedExpression::Uint(e) => f.fold_uint_expression(e).into(),
TypedExpression::Array(e) => f.fold_array_expression(e).into(),
TypedExpression::Tuple(e) => f.fold_tuple_expression(e).into(),
TypedExpression::Struct(e) => f.fold_struct_expression(e).into(),
TypedExpression::Int(e) => f.fold_int_expression(e).into(),
}
}
pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
ty: &ArrayType<'ast, T>,
@ -1132,11 +1138,7 @@ fn fold_signature<'ast, T: Field, F: Folder<'ast, T>>(
.into_iter()
.map(|o| f.fold_declaration_type(o))
.collect(),
outputs: s
.outputs
.into_iter()
.map(|o| f.fold_declaration_type(o))
.collect(),
output: box f.fold_declaration_type(*s.output),
}
}
@ -1165,54 +1167,6 @@ pub fn fold_array_expression<'ast, T: Field, F: Folder<'ast, T>>(
}
}
pub fn fold_expression_list<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
es: TypedExpressionList<'ast, T>,
) -> TypedExpressionList<'ast, T> {
let types = f.fold_types(es.types);
TypedExpressionList {
inner: f.fold_expression_list_inner(types.clone(), es.inner),
types,
}
}
pub fn fold_types<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
tys: Types<'ast, T>,
) -> Types<'ast, T> {
Types {
inner: tys.inner.into_iter().map(|t| f.fold_type(t)).collect(),
}
}
pub fn fold_expression_list_inner<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
tys: Types<'ast, T>,
es: TypedExpressionListInner<'ast, T>,
) -> TypedExpressionListInner<'ast, T> {
match es {
TypedExpressionListInner::FunctionCall(function_call) => {
match f.fold_function_call_expression(&tys, function_call) {
FunctionCallOrExpression::FunctionCall(function_call) => {
TypedExpressionListInner::FunctionCall(function_call)
}
FunctionCallOrExpression::Expression(u) => u,
}
}
TypedExpressionListInner::EmbedCall(embed, generics, arguments) => {
TypedExpressionListInner::EmbedCall(
embed,
generics,
arguments
.into_iter()
.map(|a| f.fold_expression(a))
.collect(),
)
}
}
}
pub fn fold_struct_expression<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
e: StructExpression<'ast, T>,

View file

@ -86,7 +86,7 @@ impl<'ast, T: Clone> IntegerInference for ArrayType<'ast, T> {
Ok(DeclarationArrayType::new(
self.ty
.get_common_pattern(*other.ty)
.map_err(|(t, u)| (ArrayType::new(t, s0), ArrayType::new(u, s1)))?,
.map_err(|(t, u)| (ArrayType::new(t, *s0), ArrayType::new(u, *s1)))?,
DeclarationConstant::Generic(GenericIdentifier::with_name("DUMMY")), // sizes are not checked at this stage, therefore we insert a dummy generic variable which will be equal to all possible sizes
))
}
@ -657,28 +657,28 @@ impl<'ast, T: Field> ArrayExpression<'ast, T> {
let inner_ty = res.0[0].get_type().0;
Ok(ArrayExpressionInner::Value(res).annotate(inner_ty, array_ty.size))
Ok(ArrayExpressionInner::Value(res).annotate(inner_ty, *array_ty.size))
}
ArrayExpressionInner::Repeat(box e, box count) => {
match &*target_array_ty.ty {
GType::Int => Ok(ArrayExpressionInner::Repeat(box e, box count)
.annotate(Type::Int, array_ty.size)),
.annotate(Type::Int, *array_ty.size)),
// try to align the repeated element to the target type
t => TypedExpression::align_to_type(e, t)
.map(|e| {
let ty = e.get_type().clone();
ArrayExpressionInner::Repeat(box e, box count)
.annotate(ty, array_ty.size)
.annotate(ty, *array_ty.size)
})
.map_err(|(e, _)| e),
}
}
a => {
if *target_array_ty.ty == *array_ty.ty {
Ok(a.annotate(*array_ty.ty, array_ty.size))
Ok(a.annotate(*array_ty.ty, *array_ty.size))
} else {
Err(a.annotate(*array_ty.ty, array_ty.size).into())
Err(a.annotate(*array_ty.ty, *array_ty.size).into())
}
}
}

View file

@ -22,11 +22,11 @@ pub use self::types::{
CanonicalConstantIdentifier, ConcreteFunctionKey, ConcreteSignature, ConcreteTupleType,
ConcreteType, ConstantIdentifier, DeclarationArrayType, DeclarationConstant,
DeclarationFunctionKey, DeclarationSignature, DeclarationStructType, DeclarationType,
GArrayType, GStructType, GType, GenericIdentifier, IntoTypes, Signature, StructType, TupleType,
Type, Types, UBitwidth,
GArrayType, GStructType, GType, GenericIdentifier, Signature, StructType, TupleType, Type,
UBitwidth,
};
use crate::parser::Position;
use crate::typed_absy::types::ConcreteGenericsAssignment;
use crate::typed_absy::types::{ConcreteGenericsAssignment, IntoType};
pub use self::variable::{ConcreteVariable, DeclarationVariable, GVariable, Variable};
use std::marker::PhantomData;
@ -123,21 +123,14 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
.unwrap()
})
.collect(),
outputs: main
.signature
.outputs
.iter()
.map(|ty| {
types::ConcreteType::try_from(
crate::typed_absy::types::try_from_g_type::<
DeclarationConstant<'ast, T>,
UExpression<'ast, T>,
>(ty.clone())
.unwrap(),
)
.unwrap()
})
.collect(),
output: types::ConcreteType::try_from(
crate::typed_absy::types::try_from_g_type::<
DeclarationConstant<'ast, T>,
UExpression<'ast, T>,
>(*main.signature.output.clone())
.unwrap(),
)
.unwrap(),
}
}
}
@ -362,23 +355,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> {
.join(", "),
)?;
write!(
f,
"{} {{",
match self.signature.outputs.len() {
0 => "".into(),
1 => format!(" -> {}", self.signature.outputs[0]),
_ => format!(
" -> ({})",
self.signature
.outputs
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(", ")
),
}
)?;
write!(f, " -> {} {{", self.signature.output)?;
writeln!(f)?;
@ -628,11 +605,58 @@ impl fmt::Display for RuntimeError {
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct EmbedCall<'ast, T> {
pub embed: FlatEmbed,
pub generics: Vec<u32>,
pub arguments: Vec<TypedExpression<'ast, T>>,
}
impl<'ast, T> EmbedCall<'ast, T> {
pub fn new(
embed: FlatEmbed,
generics: Vec<u32>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self {
Self {
embed,
generics,
arguments,
}
}
}
impl<'ast, T: fmt::Display> fmt::Display for EmbedCall<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.embed.id())?;
if !self.generics.is_empty() {
write!(
f,
"::<{}>",
self.generics
.iter()
.map(|g| g.to_string())
.collect::<Vec<_>>()
.join(", ")
)?;
}
write!(f, "(")?;
let len = self.arguments.len();
for (i, arg) in self.arguments.iter().enumerate() {
write!(f, "{}", arg)?;
if i < len - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
/// A statement in a `TypedFunction`
#[allow(clippy::large_enum_variant)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum TypedStatement<'ast, T> {
Return(Vec<TypedExpression<'ast, T>>),
Return(TypedExpression<'ast, T>),
Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>),
Declaration(Variable<'ast, T>),
Assertion(BooleanExpression<'ast, T>, RuntimeError),
@ -642,7 +666,7 @@ pub enum TypedStatement<'ast, T> {
UExpression<'ast, T>,
Vec<TypedStatement<'ast, T>>,
),
MultipleDefinition(Vec<TypedAssignee<'ast, T>>, TypedExpressionList<'ast, T>),
EmbedCallDefinition(TypedAssignee<'ast, T>, EmbedCall<'ast, T>),
// Aux
PushCallLog(
DeclarationFunctionKey<'ast, T>,
@ -671,15 +695,8 @@ impl<'ast, T: fmt::Display> TypedStatement<'ast, T> {
impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedStatement::Return(ref exprs) => {
write!(f, "return ")?;
for (i, expr) in exprs.iter().enumerate() {
write!(f, "{}", expr)?;
if i < exprs.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ";")
TypedStatement::Return(ref e) => {
write!(f, "return {};", e)
}
TypedStatement::Declaration(ref var) => write!(f, "{};", var),
TypedStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {};", lhs, rhs),
@ -700,14 +717,8 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> {
}
write!(f, "\t}}")
}
TypedStatement::MultipleDefinition(ref ids, ref rhs) => {
for (i, id) in ids.iter().enumerate() {
write!(f, "{}", id)?;
if i < ids.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " = {};", rhs)
TypedStatement::EmbedCallDefinition(ref lhs, ref rhs) => {
write!(f, "{} = {};", lhs, rhs)
}
TypedStatement::PushCallLog(ref key, ref generics) => write!(
f,
@ -878,41 +889,6 @@ impl<'ast, T: Clone> Typed<'ast, T> for BooleanExpression<'ast, T> {
}
}
pub trait MultiTyped<'ast, T> {
fn get_types(&self) -> &Vec<Type<'ast, T>>;
}
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct TypedExpressionList<'ast, T> {
pub inner: TypedExpressionListInner<'ast, T>,
pub types: Types<'ast, T>,
}
impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionList<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.inner)
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum TypedExpressionListInner<'ast, T> {
FunctionCall(FunctionCallExpression<'ast, T, TypedExpressionList<'ast, T>>),
EmbedCall(FlatEmbed, Vec<u32>, Vec<TypedExpression<'ast, T>>),
}
impl<'ast, T> MultiTyped<'ast, T> for TypedExpressionList<'ast, T> {
fn get_types(&self) -> &Vec<Type<'ast, T>> {
&self.types.inner
}
}
impl<'ast, T> TypedExpressionListInner<'ast, T> {
pub fn annotate(self, types: Types<'ast, T>) -> TypedExpressionList<'ast, T> {
TypedExpressionList { inner: self, types }
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct EqExpression<E> {
pub left: Box<E>,
@ -1278,7 +1254,7 @@ impl<'ast, T: Field> ArrayValue<'ast, T> {
.map(|i| {
Some(U::select(
a.clone()
.annotate(*array_ty.ty.clone(), array_ty.size.clone()),
.annotate(*array_ty.ty.clone(), *array_ty.size.clone()),
i as u32,
))
})
@ -1354,7 +1330,7 @@ impl<'ast, T: Clone> ArrayExpression<'ast, T> {
}
pub fn size(&self) -> UExpression<'ast, T> {
self.ty.size.clone()
*self.ty.size.clone()
}
}
@ -1541,15 +1517,6 @@ impl<'ast, T> From<TypedExpression<'ast, T>> for TupleExpression<'ast, T> {
}
}
// `TypedExpressionList` can technically not be constructed from `TypedExpression`
// However implementing `From<TypedExpression>` is required for `TypedExpressionList` to be `Expr`, which makes generic treatment of function calls possible
// This could maybe be avoided by splitting the `Expr` trait into many, but I did not find a way
impl<'ast, T> From<TypedExpression<'ast, T>> for TypedExpressionList<'ast, T> {
fn from(_: TypedExpression<'ast, T>) -> TypedExpressionList<'ast, T> {
unreachable!()
}
}
impl<'ast, T> From<TypedConstant<'ast, T>> for FieldElementExpression<'ast, T> {
fn from(tc: TypedConstant<'ast, T>) -> FieldElementExpression<'ast, T> {
tc.expression.into()
@ -1723,38 +1690,6 @@ impl<'ast, T: fmt::Display> fmt::Display for ArrayExpressionInner<'ast, T> {
}
}
impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionListInner<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedExpressionListInner::FunctionCall(ref function_call) => {
write!(f, "{}", function_call)
}
TypedExpressionListInner::EmbedCall(ref embed, ref generics, ref p) => {
write!(f, "{}", embed.id())?;
if !generics.is_empty() {
write!(
f,
"::<{}>",
generics
.iter()
.map(|g| g.to_string())
.collect::<Vec<_>>()
.join(", ")
)?;
}
write!(f, "(")?;
for (i, param) in p.iter().enumerate() {
write!(f, "{}", param)?;
if i < p.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
}
}
// Variable to TypedExpression conversion
impl<'ast, T: Field> From<Variable<'ast, T>> for TypedExpression<'ast, T> {
@ -1763,7 +1698,7 @@ impl<'ast, T: Field> From<Variable<'ast, T>> for TypedExpression<'ast, T> {
Type::FieldElement => FieldElementExpression::Identifier(v.id).into(),
Type::Boolean => BooleanExpression::Identifier(v.id).into(),
Type::Array(ty) => ArrayExpressionInner::Identifier(v.id)
.annotate(*ty.ty, ty.size)
.annotate(*ty.ty, *ty.size)
.into(),
Type::Struct(ty) => StructExpressionInner::Identifier(v.id).annotate(ty).into(),
Type::Tuple(ty) => TupleExpressionInner::Identifier(v.id).annotate(ty).into(),
@ -1777,7 +1712,7 @@ impl<'ast, T: Field> From<Variable<'ast, T>> for TypedExpression<'ast, T> {
pub trait Expr<'ast, T>: fmt::Display + From<TypedExpression<'ast, T>> {
type Inner;
type Ty: Clone + IntoTypes<'ast, T>;
type Ty: Clone + IntoType<'ast, T>;
fn ty(&self) -> &Self::Ty;
@ -1935,27 +1870,6 @@ impl<'ast, T: Field> Expr<'ast, T> for IntExpression<'ast, T> {
}
}
impl<'ast, T: Field> Expr<'ast, T> for TypedExpressionList<'ast, T> {
type Inner = TypedExpressionListInner<'ast, T>;
type Ty = Types<'ast, T>;
fn ty(&self) -> &Self::Ty {
&self.types
}
fn into_inner(self) -> Self::Inner {
self.inner
}
fn as_inner(&self) -> &Self::Inner {
&self.inner
}
fn as_inner_mut(&mut self) -> &mut Self::Inner {
&mut self.inner
}
}
// Enums types to enable returning e.g a member expression OR another type of expression of this type
pub enum FunctionCallOrExpression<'ast, T, E: Expr<'ast, T>> {
@ -2157,7 +2071,8 @@ impl<'ast, T: Clone> Select<'ast, T> for ArrayExpression<'ast, T> {
_ => unreachable!(),
};
ArrayExpressionInner::Select(SelectExpression::new(array, index.into())).annotate(*ty, size)
ArrayExpressionInner::Select(SelectExpression::new(array, index.into()))
.annotate(*ty, *size)
}
}
@ -2223,7 +2138,7 @@ impl<'ast, T: Clone> Member<'ast, T> for ArrayExpression<'ast, T> {
}) => (*array_ty.ty.clone(), array_ty.size.clone()),
_ => unreachable!(),
};
ArrayExpressionInner::Member(MemberExpression::new(s, id)).annotate(ty, size)
ArrayExpressionInner::Member(MemberExpression::new(s, id)).annotate(ty, *size)
}
}
@ -2289,7 +2204,7 @@ impl<'ast, T: Clone> Element<'ast, T> for ArrayExpression<'ast, T> {
Type::Array(array_ty) => (*array_ty.ty.clone(), array_ty.size.clone()),
_ => unreachable!(),
};
ArrayExpressionInner::Element(ElementExpression::new(s, id)).annotate(ty, size)
ArrayExpressionInner::Element(ElementExpression::new(s, id)).annotate(ty, *size)
}
}
@ -2355,15 +2270,6 @@ impl<'ast, T: Field> Id<'ast, T> for TupleExpression<'ast, T> {
}
}
// `TypedExpressionList` does not have an Identifier variant
// However implementing `From<TypedExpression>` is required for `TypedExpressionList` to be `Expr`, which makes generic treatment of function calls possible
// This could maybe be avoided by splitting the `Expr` trait into many, but I did not find a way
impl<'ast, T: Field> Id<'ast, T> for TypedExpressionList<'ast, T> {
fn identifier(_: Identifier<'ast>) -> Self::Inner {
unreachable!()
}
}
pub trait FunctionCall<'ast, T>: Expr<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast, T>,
@ -2432,18 +2338,6 @@ impl<'ast, T: Field> FunctionCall<'ast, T> for StructExpression<'ast, T> {
}
}
impl<'ast, T: Field> FunctionCall<'ast, T> for TypedExpressionList<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner {
TypedExpressionListInner::FunctionCall(FunctionCallExpression::new(
key, generics, arguments,
))
}
}
pub trait Block<'ast, T> {
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self;
}
@ -2471,7 +2365,7 @@ impl<'ast, T: Field> Block<'ast, T> for ArrayExpression<'ast, T> {
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self {
let array_ty = value.ty().clone();
ArrayExpressionInner::Block(BlockExpression::new(statements, value))
.annotate(*array_ty.ty, array_ty.size)
.annotate(*array_ty.ty, *array_ty.size)
}
}
@ -2592,7 +2486,7 @@ impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> {
.collect::<Vec<_>>()
.into(),
)
.annotate(*array_ty.ty, array_ty.size),
.annotate(*array_ty.ty, *array_ty.size),
ArrayExpressionInner::Slice(box a, box from, box to) => {
let from = match from.into_inner() {
UExpressionInner::Value(from) => from as usize,
@ -2618,7 +2512,7 @@ impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> {
.collect::<Vec<_>>()
.into(),
)
.annotate(*array_ty.ty, array_ty.size)
.annotate(*array_ty.ty, *array_ty.size)
}
ArrayExpressionInner::Repeat(box e, box count) => {
let count = match count.into_inner() {
@ -2631,7 +2525,7 @@ impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> {
ArrayExpressionInner::Value(
vec![TypedExpressionOrSpread::Expression(e); count].into(),
)
.annotate(*array_ty.ty, array_ty.size)
.annotate(*array_ty.ty, *array_ty.size)
}
_ => unreachable!(),
}

View file

@ -194,10 +194,6 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
}
}
fn fold_types(&mut self, tys: Types<'ast, T>) -> Result<Types<'ast, T>, Self::Error> {
fold_types(self, tys)
}
fn fold_conditional_expression<
E: Expr<'ast, T> + PartialEq + Conditional<'ast, T> + ResultFold<'ast, T>,
>(
@ -273,7 +269,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
) -> Result<ArrayType<'ast, T>, Self::Error> {
Ok(ArrayType {
ty: box self.fold_type(*t.ty)?,
size: self.fold_uint_expression(t.size)?,
size: box self.fold_uint_expression(*t.size)?,
})
}
@ -322,6 +318,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
match t {
Array(array_type) => Ok(Array(self.fold_declaration_array_type(array_type)?)),
Struct(struct_type) => Ok(Struct(self.fold_declaration_struct_type(struct_type)?)),
Tuple(tuple_type) => Ok(Tuple(self.fold_declaration_tuple_type(tuple_type)?)),
t => Ok(t),
}
}
@ -332,7 +329,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
) -> Result<DeclarationArrayType<'ast, T>, Self::Error> {
Ok(DeclarationArrayType {
ty: box self.fold_declaration_type(*t.ty)?,
size: self.fold_declaration_constant(t.size)?,
size: box self.fold_declaration_constant(*t.size)?,
})
}
@ -386,6 +383,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fold_statement(self, s)
}
fn fold_embed_call(
&mut self,
e: EmbedCall<'ast, T>,
) -> Result<EmbedCall<'ast, T>, Self::Error> {
fold_embed_call(self, e)
}
fn fold_expression_or_spread(
&mut self,
e: TypedExpressionOrSpread<'ast, T>,
@ -413,15 +417,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
&mut self,
e: TypedExpression<'ast, T>,
) -> Result<TypedExpression<'ast, T>, Self::Error> {
match e {
TypedExpression::FieldElement(e) => Ok(self.fold_field_expression(e)?.into()),
TypedExpression::Boolean(e) => Ok(self.fold_boolean_expression(e)?.into()),
TypedExpression::Uint(e) => Ok(self.fold_uint_expression(e)?.into()),
TypedExpression::Array(e) => Ok(self.fold_array_expression(e)?.into()),
TypedExpression::Struct(e) => Ok(self.fold_struct_expression(e)?.into()),
TypedExpression::Tuple(e) => Ok(self.fold_tuple_expression(e)?.into()),
TypedExpression::Int(e) => Ok(self.fold_int_expression(e)?.into()),
}
fold_expression(self, e)
}
fn fold_array_expression(
@ -445,21 +441,6 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fold_tuple_expression(self, e)
}
fn fold_expression_list_inner(
&mut self,
tys: &Types<'ast, T>,
es: TypedExpressionListInner<'ast, T>,
) -> Result<TypedExpressionListInner<'ast, T>, Self::Error> {
fold_expression_list_inner(self, tys, es)
}
fn fold_expression_list(
&mut self,
es: TypedExpressionList<'ast, T>,
) -> Result<TypedExpressionList<'ast, T>, Self::Error> {
fold_expression_list(self, es)
}
fn fold_int_expression(
&mut self,
e: IntExpression<'ast, T>,
@ -523,12 +504,7 @@ pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>(
s: TypedStatement<'ast, T>,
) -> Result<Vec<TypedStatement<'ast, T>>, F::Error> {
let res = match s {
TypedStatement::Return(expressions) => TypedStatement::Return(
expressions
.into_iter()
.map(|e| f.fold_expression(e))
.collect::<Result<_, _>>()?,
),
TypedStatement::Return(e) => TypedStatement::Return(f.fold_expression(e)?),
TypedStatement::Definition(a, e) => {
TypedStatement::Definition(f.fold_assignee(a)?, f.fold_expression(e)?)
}
@ -548,18 +524,31 @@ pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>(
.flatten()
.collect(),
),
TypedStatement::MultipleDefinition(variables, elist) => TypedStatement::MultipleDefinition(
variables
.into_iter()
.map(|v| f.fold_assignee(v))
.collect::<Result<_, _>>()?,
f.fold_expression_list(elist)?,
),
TypedStatement::EmbedCallDefinition(assignee, embed_call) => {
TypedStatement::EmbedCallDefinition(
f.fold_assignee(assignee)?,
f.fold_embed_call(embed_call)?,
)
}
s => s,
};
Ok(vec![res])
}
pub fn fold_embed_call<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
e: EmbedCall<'ast, T>,
) -> Result<EmbedCall<'ast, T>, F::Error> {
Ok(EmbedCall {
arguments: e
.arguments
.into_iter()
.map(|s| f.fold_expression(s))
.collect::<Result<Vec<_>, _>>()?,
..e
})
}
pub fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
ty: &ArrayType<'ast, T>,
@ -1200,11 +1189,7 @@ pub fn fold_signature<'ast, T: Field, F: ResultFolder<'ast, T>>(
.into_iter()
.map(|o| f.fold_declaration_type(o))
.collect::<Result<_, _>>()?,
outputs: s
.outputs
.into_iter()
.map(|o| f.fold_declaration_type(o))
.collect::<Result<_, _>>()?,
output: box f.fold_declaration_type(*s.output)?,
})
}
@ -1223,6 +1208,21 @@ pub fn fold_declaration_constant<'ast, T: Field, F: ResultFolder<'ast, T>>(
}
}
pub fn fold_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
e: TypedExpression<'ast, T>,
) -> Result<TypedExpression<'ast, T>, F::Error> {
match e {
TypedExpression::FieldElement(e) => Ok(f.fold_field_expression(e)?.into()),
TypedExpression::Boolean(e) => Ok(f.fold_boolean_expression(e)?.into()),
TypedExpression::Uint(e) => Ok(f.fold_uint_expression(e)?.into()),
TypedExpression::Array(e) => Ok(f.fold_array_expression(e)?.into()),
TypedExpression::Struct(e) => Ok(f.fold_struct_expression(e)?.into()),
TypedExpression::Tuple(e) => Ok(f.fold_tuple_expression(e)?.into()),
TypedExpression::Int(e) => Ok(f.fold_int_expression(e)?.into()),
}
}
pub fn fold_array_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
e: ArrayExpression<'ast, T>,
@ -1235,58 +1235,6 @@ pub fn fold_array_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
})
}
pub fn fold_expression_list<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
es: TypedExpressionList<'ast, T>,
) -> Result<TypedExpressionList<'ast, T>, F::Error> {
let types = f.fold_types(es.types)?;
Ok(TypedExpressionList {
inner: f.fold_expression_list_inner(&types, es.inner)?,
types,
})
}
pub fn fold_types<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
tys: Types<'ast, T>,
) -> Result<Types<'ast, T>, F::Error> {
Ok(Types {
inner: tys
.inner
.into_iter()
.map(|t| f.fold_type(t))
.collect::<Result<_, _>>()?,
})
}
pub fn fold_expression_list_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
tys: &Types<'ast, T>,
es: TypedExpressionListInner<'ast, T>,
) -> Result<TypedExpressionListInner<'ast, T>, F::Error> {
match es {
TypedExpressionListInner::FunctionCall(function_call) => {
match f.fold_function_call_expression(tys, function_call)? {
FunctionCallOrExpression::FunctionCall(function_call) => {
Ok(TypedExpressionListInner::FunctionCall(function_call))
}
FunctionCallOrExpression::Expression(list) => Ok(list),
}
}
TypedExpressionListInner::EmbedCall(embed, generics, arguments) => {
Ok(TypedExpressionListInner::EmbedCall(
embed,
generics,
arguments
.into_iter()
.map(|a| f.fold_expression(a))
.collect::<Result<_, _>>()?,
))
}
}
}
pub fn fold_struct_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
e: StructExpression<'ast, T>,

View file

@ -8,62 +8,37 @@ use std::fmt;
use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf};
pub trait IntoTypes<'ast, T> {
fn into_types(self) -> Types<'ast, T>;
pub trait IntoType<'ast, T> {
fn into_type(self) -> Type<'ast, T>;
}
impl<'ast, T> IntoTypes<'ast, T> for Type<'ast, T> {
fn into_types(self) -> Types<'ast, T> {
Types { inner: vec![self] }
}
}
impl<'ast, T> IntoTypes<'ast, T> for StructType<'ast, T> {
fn into_types(self) -> Types<'ast, T> {
Types {
inner: vec![Type::Struct(self)],
}
}
}
impl<'ast, T> IntoTypes<'ast, T> for ArrayType<'ast, T> {
fn into_types(self) -> Types<'ast, T> {
Types {
inner: vec![Type::Array(self)],
}
}
}
impl<'ast, T> IntoTypes<'ast, T> for TupleType<'ast, T> {
fn into_types(self) -> Types<'ast, T> {
Types {
inner: vec![Type::Tuple(self)],
}
}
}
impl<'ast, T> IntoTypes<'ast, T> for UBitwidth {
fn into_types(self) -> Types<'ast, T> {
Types {
inner: vec![Type::Uint(self)],
}
}
}
impl<'ast, T> IntoTypes<'ast, T> for Types<'ast, T> {
fn into_types(self) -> Types<'ast, T> {
impl<'ast, T> IntoType<'ast, T> for Type<'ast, T> {
fn into_type(self) -> Type<'ast, T> {
self
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct Types<'ast, T> {
pub inner: Vec<Type<'ast, T>>,
impl<'ast, T> IntoType<'ast, T> for StructType<'ast, T> {
fn into_type(self) -> Type<'ast, T> {
Type::Struct(self)
}
}
impl<'ast, T> Types<'ast, T> {
pub fn new(types: Vec<Type<'ast, T>>) -> Self {
Self { inner: types }
impl<'ast, T> IntoType<'ast, T> for ArrayType<'ast, T> {
fn into_type(self) -> Type<'ast, T> {
Type::Array(self)
}
}
impl<'ast, T> IntoType<'ast, T> for TupleType<'ast, T> {
fn into_type(self) -> Type<'ast, T> {
Type::Tuple(self)
}
}
impl<'ast, T> IntoType<'ast, T> for UBitwidth {
fn into_type(self) -> Type<'ast, T> {
Type::Uint(self)
}
}
@ -337,7 +312,7 @@ impl<'ast, T> From<ConcreteStructMember> for StructMember<'ast, T> {
#[derive(Clone, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Debug)]
pub struct GArrayType<S> {
pub size: S,
pub size: Box<S>,
#[serde(flatten)]
pub ty: Box<GType<S>>,
}
@ -348,7 +323,7 @@ pub type ArrayType<'ast, T> = GArrayType<UExpression<'ast, T>>;
impl<'ast, S, R: PartialEq<S>> PartialEq<GArrayType<S>> for GArrayType<R> {
fn eq(&self, other: &GArrayType<S>) -> bool {
*self.ty == *other.ty && self.size == other.size
*self.ty == *other.ty && *self.size == *other.size
}
}
@ -382,7 +357,7 @@ fn try_from_g_array_type<T: TryInto<U>, U>(
t: GArrayType<T>,
) -> Result<GArrayType<U>, SpecializationError> {
Ok(GArrayType {
size: t.size.try_into().map_err(|_| SpecializationError)?,
size: box (*t.size).try_into().map_err(|_| SpecializationError)?,
ty: box try_from_g_type(*t.ty)?,
})
}
@ -830,7 +805,7 @@ impl<S, U: Into<S>> From<(GType<S>, U)> for GArrayType<S> {
fn from(tup: (GType<S>, U)) -> Self {
GArrayType {
ty: box tup.0,
size: tup.1.into(),
size: box tup.1.into(),
}
}
}
@ -838,8 +813,8 @@ impl<S, U: Into<S>> From<(GType<S>, U)> for GArrayType<S> {
impl<S> GArrayType<S> {
pub fn new<U: Into<S>>(ty: GType<S>, size: U) -> Self {
GArrayType {
ty: Box::new(ty),
size: size.into(),
ty: box ty,
size: box size.into(),
}
}
}
@ -922,7 +897,7 @@ impl<'ast, T: fmt::Display + PartialEq + fmt::Debug> Type<'ast, T> {
(Array(l), Array(r)) => match l.ty.can_be_specialized_to(&r.ty) {
true => {
// check the size if types match
match (&l.size.as_inner(), &r.size) {
match (&l.size.as_inner(), &*r.size) {
// compare the sizes for concrete ones
(UExpressionInner::Value(v), DeclarationConstant::Concrete(c)) => {
(*v as u32) == *c
@ -953,7 +928,7 @@ impl ConcreteType {
GType::Boolean => 1,
GType::Uint(_) => 1,
GType::Array(array_type) => {
array_type.size as usize * array_type.ty.get_primitive_count()
*array_type.size as usize * array_type.ty.get_primitive_count()
}
GType::Tuple(tuple_type) => tuple_type
.elements
@ -1123,7 +1098,7 @@ pub fn check_type<'ast, T, S: Clone + PartialEq + PartialEq<u32>>(
(DeclarationType::Array(t0), GType::Array(t1)) => {
// both the inner type and the size must match
check_type(&t0.ty, &t1.ty, constants)
&& check_generic(&t0.size, Some(&t1.size), constants)
&& check_generic(&*t0.size, Some(&*t1.size), constants)
}
(DeclarationType::FieldElement, GType::FieldElement)
| (DeclarationType::Boolean, GType::Boolean) => true,
@ -1164,7 +1139,7 @@ impl<'ast, T> From<CanonicalConstantIdentifier<'ast>> for DeclarationConstant<'a
pub fn specialize_declaration_type<
'ast,
T: Clone,
S: Clone + PartialEq + From<u32> + fmt::Debug + From<CanonicalConstantIdentifier<'ast>>,
S: Clone + PartialEq + From<u32> + From<CanonicalConstantIdentifier<'ast>>,
>(
decl_ty: DeclarationType<'ast, T>,
generics: &GGenericsAssignment<'ast, S>,
@ -1172,10 +1147,10 @@ pub fn specialize_declaration_type<
Ok(match decl_ty {
DeclarationType::Int => unreachable!(),
DeclarationType::Array(t0) => {
let ty = box specialize_declaration_type(*t0.ty, generics)?;
let ty = specialize_declaration_type(*t0.ty, generics)?;
let size = t0.size.map(generics)?;
GType::Array(GArrayType { size, ty })
GType::Array(GArrayType::new(ty, size))
}
DeclarationType::Tuple(t0) => {
let elements = t0
@ -1244,12 +1219,22 @@ pub mod signature {
pub struct GSignature<S> {
pub generics: Vec<Option<S>>,
pub inputs: Vec<GType<S>>,
pub outputs: Vec<GType<S>>,
pub output: Box<GType<S>>,
}
impl<S> Default for GSignature<S> {
fn default() -> Self {
Self {
generics: vec![],
inputs: vec![],
output: box GType::Tuple(GTupleType::new(vec![])),
}
}
}
impl<S: PartialEq> PartialEq for GSignature<S> {
fn eq(&self, other: &Self) -> bool {
self.inputs == other.inputs && self.outputs == other.outputs
self.inputs == other.inputs && self.output == other.output
}
}
@ -1257,7 +1242,7 @@ pub mod signature {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.inputs
.partial_cmp(&other.inputs)
.map(|c| self.outputs.partial_cmp(&other.outputs).map(|d| c.then(d)))
.map(|c| self.output.partial_cmp(&other.output).map(|d| c.then(d)))
.unwrap()
}
}
@ -1271,17 +1256,7 @@ pub mod signature {
impl<S: Hash> Hash for GSignature<S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.inputs.hash(state);
self.outputs.hash(state);
}
}
impl<S> Default for GSignature<S> {
fn default() -> Self {
GSignature {
generics: vec![],
inputs: vec![],
outputs: vec![],
}
self.output.hash(state);
}
}
@ -1297,13 +1272,13 @@ pub mod signature {
other
.inputs
.iter()
.chain(other.outputs.iter())
.zip(self.inputs.iter().chain(self.outputs.iter()))
.chain(std::iter::once(&*other.output))
.zip(self.inputs.iter().chain(std::iter::once(&*self.output)))
.all(|(decl_ty, ty)| check_type::<T, u32>(decl_ty, ty, &mut constants))
}
}
impl<'ast, T: Clone + PartialEq + fmt::Debug> DeclarationSignature<'ast, T> {
impl<'ast, T: Clone + PartialEq> DeclarationSignature<'ast, T> {
pub fn specialize(
&self,
values: Vec<Option<u32>>,
@ -1312,9 +1287,8 @@ pub mod signature {
// we keep track of the value of constants in a map, as a given constant can only have one value
let mut constants = ConcreteGenericsAssignment::default();
assert_eq!(self.inputs.len(), signature.inputs.len());
assert_eq!(self.outputs.len(), signature.outputs.len());
assert_eq!(self.generics.len(), values.len());
assert_eq!(self.inputs.len(), signature.inputs.len());
let decl_generics = self.generics.iter().map(|g| match g.clone().unwrap() {
DeclarationConstant::Generic(g) => g,
@ -1330,8 +1304,13 @@ pub mod signature {
let condition = self
.inputs
.iter()
.chain(self.outputs.iter())
.zip(signature.inputs.iter().chain(signature.outputs.iter()))
.chain(std::iter::once(&*self.output))
.zip(
signature
.inputs
.iter()
.chain(std::iter::once(&*signature.output)),
)
.all(|(decl_ty, ty)| check_type(decl_ty, ty, &mut constants));
if constants.0.len() != self.generics.len() {
@ -1344,11 +1323,11 @@ pub mod signature {
}
}
pub fn get_output_types(
pub fn get_output_type(
&self,
generics: Vec<Option<UExpression<'ast, T>>>,
inputs: Vec<Type<'ast, T>>,
) -> Result<Vec<Type<'ast, T>>, GenericIdentifier<'ast>> {
) -> Result<Type<'ast, T>, GenericIdentifier<'ast>> {
// we keep track of the value of constants in a map, as a given constant can only have one value
let mut constants = GenericsAssignment::default();
@ -1375,12 +1354,8 @@ pub mod signature {
.zip(inputs.iter())
.all(|(decl_ty, ty)| check_type(decl_ty, ty, &mut constants));
// get the outputs from the map
self.outputs
.clone()
.into_iter()
.map(|t| specialize_declaration_type(t, &constants))
.collect::<Result<_, _>>()
// get the specialized output
specialize_declaration_type(*self.output.clone(), &constants)
}
}
@ -1401,11 +1376,7 @@ pub mod signature {
.into_iter()
.map(try_from_g_type)
.collect::<Result<_, _>>()?,
outputs: t
.outputs
.into_iter()
.map(try_from_g_type)
.collect::<Result<_, _>>()?,
output: box try_from_g_type(*t.output)?,
})
}
@ -1453,21 +1424,7 @@ pub mod signature {
write!(f, ", ")?;
}
}
write!(f, ")")?;
match self.outputs.len() {
0 => write!(f, ""),
1 => write!(f, " -> {}", self.outputs[0]),
_ => {
write!(f, " -> (")?;
for (i, t) in self.outputs.iter().enumerate() {
write!(f, "{}", t)?;
if i < self.outputs.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
write!(f, ") -> {}", self.output)
}
}
@ -1486,8 +1443,8 @@ pub mod signature {
self
}
pub fn outputs(mut self, outputs: Vec<GType<S>>) -> Self {
self.outputs = outputs;
pub fn output(mut self, output: GType<S>) -> Self {
self.output = Box::new(output);
self
}
}
@ -1501,7 +1458,7 @@ pub mod signature {
fn signature() {
let s = ConcreteSignature::new()
.inputs(vec![ConcreteType::FieldElement, ConcreteType::Boolean])
.outputs(vec![ConcreteType::Boolean]);
.output(ConcreteType::Boolean);
assert_eq!(s.to_string(), String::from("(field, bool) -> bool"));
}

View file

@ -5,7 +5,7 @@ impl From<typed_absy::types::ConcreteSignature> for zir::types::Signature {
fn from(s: typed_absy::types::ConcreteSignature) -> zir::types::Signature {
zir::types::Signature {
inputs: s.inputs.into_iter().flat_map(from_type).collect(),
outputs: s.outputs.into_iter().flat_map(from_type).collect(),
outputs: from_type(*s.output),
}
}
}
@ -20,7 +20,7 @@ fn from_type(t: typed_absy::types::ConcreteType) -> Vec<zir::types::Type> {
}
typed_absy::types::ConcreteType::Array(array_type) => {
let inner = from_type(*array_type.ty);
(0..array_type.size).flat_map(|_| inner.clone()).collect()
(0..*array_type.size).flat_map(|_| inner.clone()).collect()
}
typed_absy::types::ConcreteType::Struct(members) => members
.into_iter()

View file

@ -1,6 +1,6 @@
import "utils/pack/bool/nonStrictUnpack256.zok" as unpack256;
def main(field[2] inputs) -> (bool[512]) {
def main(field[2] inputs) -> bool[512] {
bool[512] preimage512 = [...unpack256(inputs[0]), ...unpack256(inputs[1])];
return preimage512;
}

View file

@ -1,3 +1,3 @@
def main(bool[3] a) -> (bool[3]) {
def main(bool[3] a) -> bool[3] {
return a;
}

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},

View file

@ -7,7 +7,7 @@
},
"output": {
"Ok": {
"values": [{"a": [true, true], "b": "3"}, "4"]
"values": [[{"a": [true, true], "b": "3"}, "4"]]
}
}
}

View file

@ -4,10 +4,10 @@ struct Foo {
}
def f(bool a, field b, Foo c, field[2] d) -> (Foo, field) {
return Foo { a: [a, a], b: d[0] }, c.a[0] ? b + c.b : d[1];
return (Foo { a: [a, a], b: d[0] }, c.a[0] ? b + c.b : d[1]);
}
def main(bool a, field b, Foo c, field[2] d) -> (Foo, field) {
Foo e, field f = f(a, b, c, d);
return e, f;
(Foo, field) r = f(a, b, c, d);
return r;
}

View file

@ -3,13 +3,11 @@
"tests": [
{
"input": {
"values": [
]
"values": []
},
"output": {
"Ok": {
"values": [
]
"values": [[]]
}
}
}

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -7,7 +7,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": [true, true]
"values": [[true, true]]
}
}
},
@ -18,7 +18,7 @@
},
"output": {
"Ok": {
"values": [true, true]
"values": [[true, true]]
}
}
},
@ -28,7 +28,7 @@
},
"output": {
"Ok": {
"values": [true, true]
"values": [[true, true]]
}
}
},
@ -38,7 +38,7 @@
},
"output": {
"Ok": {
"values": [true, true]
"values": [[true, true]]
}
}
},
@ -48,7 +48,7 @@
},
"output": {
"Ok": {
"values": [true, true]
"values": [[true, true]]
}
}
},
@ -58,7 +58,7 @@
},
"output": {
"Ok": {
"values": [false, false]
"values": [[false, false]]
}
}
},
@ -68,7 +68,7 @@
},
"output": {
"Ok": {
"values": [false, false]
"values": [[false, false]]
}
}
},
@ -78,7 +78,7 @@
},
"output": {
"Ok": {
"values": [false, false]
"values": [[false, false]]
}
}
}

View file

@ -41,5 +41,5 @@ def main(field a, u32 b) -> (bool, bool) {
field c = 42;
u32 d = 42;
return le::<FIELD_SIZE_IN_BITS>(a, c), le(b, d);
return (le::<FIELD_SIZE_IN_BITS>(a, c), le(b, d));
}

View file

@ -7,7 +7,7 @@
},
"output": {
"Ok": {
"values": [["21888242871839275222246405745257275088548364400416034343698204186575808495615", "21888242871839275222246405745257275088548364400416034343698204186575808495616", "21888242871839275222246405745257275088548364400416034343698204186575808495616", "21888242871839275222246405745257275088548364400416034343698204186575808495616"], ["0xfe", "0xff", "0xff", "0xff"]]
"values": [[["21888242871839275222246405745257275088548364400416034343698204186575808495615", "21888242871839275222246405745257275088548364400416034343698204186575808495616", "21888242871839275222246405745257275088548364400416034343698204186575808495616", "21888242871839275222246405745257275088548364400416034343698204186575808495616"], ["0xfe", "0xff", "0xff", "0xff"]]]
}
}
}

View file

@ -12,5 +12,5 @@ def main(field x, field y, u8 z, u8 t) -> (field[4], u8[4]) {
assert(-0x00 == 0x00);
assert(-0f == 0);
return [a, b, c, d], [e, f, g, h];
return ([a, b, c, d], [e, f, g, h]);
}

View file

@ -7,7 +7,7 @@
},
"output": {
"Ok": {
"values": ["4838400", "10", "25"]
"values": [["4838400", "10", "25"]]
}
}
},
@ -17,7 +17,7 @@
},
"output": {
"Ok": {
"values": ["0", "10", "25"]
"values": [["0", "10", "25"]]
}
}
}

View file

@ -24,5 +24,5 @@ def main(field[4] values) -> (field, field, field) {
}
}
return res0, res1, res2;
return (res0, res1, res2);
}

View file

@ -28,7 +28,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -7,12 +7,7 @@
"tests": [
{
"input": {
"values": [
true,
["42",
"42"],
"0"
]
"values": [true, ["42", "42"], "0"]
},
"output": {
"Err": {
@ -28,41 +23,21 @@
},
{
"input": {
"values": [
true,
["1",
"1"],
"1"
]
"values": [true, ["1", "1"], "1"]
},
"output": {
"Ok": {
"values": [
true,
["1",
"1"],
"1"
]
"values": [[true, ["1", "1"], "1"]]
}
}
},
{
"input": {
"values": [
false,
["2",
"2"],
"0"
]
"values": [false, ["2", "2"], "0"]
},
"output": {
"Ok": {
"values": [
false,
["2",
"2"],
"0"
]
"values": [[false, ["2", "2"], "0"]]
}
}
}

View file

@ -32,7 +32,7 @@ def main(bool condition, field[2] a, field x) -> (bool, field[2], field) {
// first branch asserts that `condition` is true, second branch asserts that `condition` is false. This should never throw.
// first branch asserts that all elements in `a` are 1, 2 in the second branch. This should throw only if `a` is neither ones or zeroes
// first branch asserts that `x` is zero and returns it, second branch asserts that `x` isn't 0 and returns its inverse (which internally generates a failing assert if x is 0). This should never throw
return condition ? yes(condition) : no(condition), \
return (condition ? yes(condition) : no(condition), \
condition ? ones(a) : twos(a), \
x == 0 ? zero(x) : inverse(x);
x == 0 ? zero(x) : inverse(x));
}

View file

@ -7,12 +7,7 @@
"tests": [
{
"input": {
"values": [
true,
["1",
"1"],
"1"
]
"values": [true, ["1", "1"], "1"]
},
"output": {
"Err": {

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": [["2"], ["1"], { "a": "2"}, {"a": "1"}, "2", "1"]
"values": [[["2"], ["1"], { "a": "2"}, {"a": "1"}, "2", "1"]]
}
}
}

View file

@ -18,5 +18,5 @@ def mutate(field[1] f) -> field[1] {
}
def main(field[1] f, Foo g, field h) -> (field[1], field[1], Foo, Foo, field, field) {
return mutate(f), f, mutate(g), g, mutate(h), h;
return (mutate(f), f, mutate(g), g, mutate(h), h);
}

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -37,7 +37,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},
@ -47,7 +47,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -51,7 +51,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -37,7 +37,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -9,7 +9,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},
@ -19,7 +19,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},

View file

@ -9,7 +9,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},
@ -19,7 +19,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},

View file

@ -9,7 +9,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},
@ -19,7 +19,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},

View file

@ -9,7 +9,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},
@ -19,7 +19,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
},

View file

@ -1,3 +1,3 @@
def main(field[3] a, field[3] b, field c) -> (field[9]) {
def main(field[3] a, field[3] b, field c) -> field[9] {
return [...a[..2], ...b[1..], ...a[..], ...b[1..2], c];
}

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -3,6 +3,6 @@ struct A {
bool b;
}
def main(A a) -> (A) {
def main(A a) -> A {
return a;
}

View file

@ -12,7 +12,7 @@
},
"output": {
"Ok": {
"values": []
"values": [[]]
}
}
}

View file

@ -1,4 +1,4 @@
def main(bool flag) -> ((field, field)) {
def main(bool flag) -> (field, field) {
(field, field) a = flag ? (1f, 2f) : (2f, 1f);
return a;
}

Some files were not shown because too many files have changed in this diff Show more