diff --git a/zokrates_cli/examples/compile_errors/generics/unused.zok b/zokrates_cli/examples/compile_errors/generics/generic_in_main.zok similarity index 100% rename from zokrates_cli/examples/compile_errors/generics/unused.zok rename to zokrates_cli/examples/compile_errors/generics/generic_in_main.zok diff --git a/zokrates_cli/examples/compile_errors/generics/generic_inference.zok b/zokrates_cli/examples/compile_errors/generics/generic_inference.zok new file mode 100644 index 00000000..82c95f5f --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/generic_inference.zok @@ -0,0 +1,7 @@ +struct A { + field[N] a +} + +def main(): + A<_> a = A { a: [1] } + return \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/struct_generic_mismatch.zok b/zokrates_cli/examples/compile_errors/generics/struct_generic_mismatch.zok new file mode 100644 index 00000000..b110cd58 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/struct_generic_mismatch.zok @@ -0,0 +1,6 @@ +struct A { + field[N] a +} + +def main(A<1> a, A<2> b) -> bool: + return a == b \ No newline at end of file diff --git a/zokrates_cli/examples/compile_errors/generics/unused_struct_generic.zok b/zokrates_cli/examples/compile_errors/generics/unused_struct_generic.zok new file mode 100644 index 00000000..03f97145 --- /dev/null +++ b/zokrates_cli/examples/compile_errors/generics/unused_struct_generic.zok @@ -0,0 +1,4 @@ +struct A {} + +def main(): + return \ No newline at end of file diff --git a/zokrates_core/src/semantics.rs b/zokrates_core/src/semantics.rs index 2a89dc17..3a2546c7 100644 --- a/zokrates_core/src/semantics.rs +++ b/zokrates_core/src/semantics.rs @@ -1216,18 +1216,26 @@ impl<'ast, T: Field> Checker<'ast, T> { let assignment = GGenericsAssignment(generics .into_iter() .zip(generic_identifiers) - .filter_map(|(e, g)| e.map(|e| { - self - .check_expression(e, module_id, types) - .and_then(|e| { - UExpression::try_from_typed(e, &UBitwidth::B32) - .map(|e| (g, e)) - .map_err(|e| ErrorInner { - pos: Some(pos), - message: format!("Expected u32 expression, but got expression of type {}", e.get_type()), - }) - }) - })) + .map(|(e, g)| match e { + Some(e) => { + self + .check_expression(e, module_id, types) + .and_then(|e| { + UExpression::try_from_typed(e, &UBitwidth::B32) + .map(|e| (g, e)) + .map_err(|e| ErrorInner { + pos: Some(pos), + message: format!("Expected u32 expression, but got expression of type {}", e.get_type()), + }) + }) + }, + None => Err(ErrorInner { + pos: Some(pos), + message: + "Expected u32 constant or identifier, but found `_`. Generic inference is not supported yet." + .into(), + }) + }) .collect::>()?); // specialize the declared type using the generic assignment diff --git a/zokrates_core/src/static_analysis/propagation.rs b/zokrates_core/src/static_analysis/propagation.rs index 5d51a05a..c5989c21 100644 --- a/zokrates_core/src/static_analysis/propagation.rs +++ b/zokrates_core/src/static_analysis/propagation.rs @@ -1279,6 +1279,24 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { Ok(BooleanExpression::ArrayEq(box e1, box e2)) } + BooleanExpression::StructEq(box e1, box e2) => { + let e1 = self.fold_struct_expression(e1)?; + let e2 = self.fold_struct_expression(e2)?; + + if let (Ok(t1), Ok(t2)) = ( + ConcreteType::try_from(e1.get_type()), + ConcreteType::try_from(e2.get_type()), + ) { + if t1 != t2 { + return Err(Error::Type(format!( + "Cannot compare {} of type {} to {} of type {}", + e1, t1, e2, t2 + ))); + } + }; + + Ok(BooleanExpression::StructEq(box e1, box e2)) + } BooleanExpression::FieldLt(box e1, box e2) => { let e1 = self.fold_field_expression(e1)?; let e2 = self.fold_field_expression(e2)?; diff --git a/zokrates_core/src/typed_absy/abi.rs b/zokrates_core/src/typed_absy/abi.rs index db30311a..15554a73 100644 --- a/zokrates_core/src/typed_absy/abi.rs +++ b/zokrates_core/src/typed_absy/abi.rs @@ -230,12 +230,15 @@ mod tests { public: true, ty: ConcreteType::Struct(ConcreteStructType::new( "".into(), - "Foo".into(), - vec![], - vec![ - ConcreteStructMember::new(String::from("a"), ConcreteType::FieldElement), - ConcreteStructMember::new(String::from("b"), ConcreteType::Boolean), - ], + "Bar".into(), + vec![Some(1usize)], + vec![ConcreteStructMember::new( + String::from("a"), + ConcreteType::Array(ConcreteArrayType::new( + ConcreteType::FieldElement, + 1usize, + )), + )], )), }], outputs: vec![ConcreteType::Struct(ConcreteStructType::new( @@ -259,16 +262,18 @@ mod tests { "public": true, "type": "struct", "components": { - "name": "Foo", - "generics": [], + "name": "Bar", + "generics": [ + 1 + ], "members": [ { "name": "a", - "type": "field" - }, - { - "name": "b", - "type": "bool" + "type": "array", + "components": { + "size": 1, + "type": "field" + } } ] }