1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

clean, allow literal in explicit constant parameter, add tests

This commit is contained in:
schaeff 2021-01-18 15:18:36 +01:00
parent 5fe05099b3
commit 2a2da0173f
6 changed files with 150 additions and 366 deletions

View file

@ -539,11 +539,14 @@ impl<'ast> From<pest::PostfixExpression<'ast>> for absy::ExpressionNode<'ast> {
&id_str,
a.explicit_generics.map(|explicit_generics| {
explicit_generics
.identifiers_or_underscores
.values
.into_iter()
.map(|i| match i {
pest::IdentifierExpressionOrUnderscore::Underscore(_) => None,
pest::IdentifierExpressionOrUnderscore::Identifier(i) => {
pest::ConstantGenericValue::Underscore(_) => None,
pest::ConstantGenericValue::Value(v) => {
Some(absy::ExpressionNode::from(v))
}
pest::ConstantGenericValue::Identifier(i) => {
Some(absy::Expression::Identifier(i.span.as_str()).span(i.span))
}
})

View file

@ -756,21 +756,6 @@ impl<'ast, T: Field> Checker<'ast, T> {
})
}
fn check_parameter(
&mut self,
p: ParameterNode<'ast>,
module_id: &ModuleId,
types: &TypeMap<'ast>,
constants: &HashSet<Identifier<'ast>>,
) -> Result<DeclarationParameter<'ast>, Vec<ErrorInner>> {
let var = self.check_declaration_variable(p.value.id, module_id, types, constants)?;
Ok(DeclarationParameter {
id: var,
private: p.value.private,
})
}
fn check_signature(
&mut self,
signature: UnresolvedSignature<'ast>,
@ -989,20 +974,6 @@ impl<'ast, T: Field> Checker<'ast, T> {
))
}
fn check_declaration_variable(
&mut self,
v: crate::absy::VariableNode<'ast>,
module_id: &ModuleId,
types: &TypeMap<'ast>,
constants: &HashSet<Identifier<'ast>>,
) -> Result<DeclarationVariable<'ast>, Vec<ErrorInner>> {
Ok(DeclarationVariable::with_id_and_type(
v.value.id,
self.check_declaration_type(v.value._type, module_id, types, constants)
.map_err(|e| vec![e])?,
))
}
fn check_for_loop(
&mut self,
var: crate::absy::VariableNode<'ast>,
@ -1273,22 +1244,27 @@ impl<'ast, T: Field> Checker<'ast, T> {
// Right side has to be a function call
Expression::FunctionCall(fun_id, generics, arguments) => {
// check the generic arguments, if any
let generics_checked: Option<Vec<Option<TypedExpression<'ast, T>>>> = generics
let generics_checked: Option<Vec<Option<UExpression<'ast, T>>>> = generics
.map(|generics|
generics.into_iter().map(|g|
g.map(|g|
self.check_expression(g, module_id, &types)
)
g.map(|g| {
let pos = g.pos();
self.check_expression(g, module_id, &types).and_then(|g| match g {
TypedExpression::Uint(e) if e.bitwidth() == UBitwidth::B32 => { Ok(e) },
e => Err(ErrorInner {
pos: Some(pos),
message: format!(
"Expected {} to be of type u32, found {}",
e,
e.get_type(),
),
})
})
})
.transpose()
)
.collect::<Result<_, _>>()
.map_err(|e| vec![e])
).transpose()?;
let generics_checked = generics_checked.map(|generics_checked| generics_checked.into_iter().map(|g| g.map(|g| match g {
TypedExpression::Uint(e) => if e.bitwidth() == UBitwidth::B32 { Ok(e) } else { Err(unimplemented!()) },
_ => Err(unimplemented!())
}).transpose()).collect::<Result<_, _>>().map_err(|e| vec![e])).transpose()?;
).transpose().map_err(|e| vec![e])?;
// check lhs assignees are defined
let (assignees, errors): (Vec<_>, Vec<_>) = assignees.into_iter().map(|a| self.check_assignee(a, module_id, types)).partition(|r| r.is_ok());
@ -1831,32 +1807,25 @@ impl<'ast, T: Field> Checker<'ast, T> {
Expression::U32Constant(n) => Ok(UExpressionInner::Value(n.into()).annotate(32).into()),
Expression::FunctionCall(fun_id, generics, arguments) => {
// check the generic arguments, if any
let generics_checked: Option<Vec<Option<TypedExpression<'ast, T>>>> = generics
let generics_checked: Option<Vec<Option<UExpression<'ast, T>>>> = generics
.map(|generics| {
generics
.into_iter()
.map(|g| {
g.map(|g| self.check_expression(g, module_id, &types))
.transpose()
})
.collect::<Result<_, _>>()
})
.transpose()?;
let generics_checked = generics_checked
.map(|generics_checked| {
generics_checked
.into_iter()
.map(|g| {
g.map(|g| match g {
TypedExpression::Uint(e) => {
if e.bitwidth() == UBitwidth::B32 {
Ok(e)
} else {
Err(unimplemented!())
}
}
_ => Err(unimplemented!()),
g.map(|g| {
let pos = g.pos();
self.check_expression(g, module_id, &types).and_then(|g| {
UExpression::try_from_typed(g, UBitwidth::B32).map_err(
|e| ErrorInner {
pos: Some(pos),
message: format!(
"Expected {} to be of type u32, found {}",
e,
e.get_type(),
),
},
)
})
})
.transpose()
})
@ -2941,6 +2910,8 @@ mod tests {
#[test]
fn field_in_range() {
// The value of `P - 1` is a valid field literal
let types = HashMap::new();
let module_id = "".into();
@ -2954,6 +2925,8 @@ mod tests {
#[test]
fn field_overflow() {
// the value of `P` is an invalid field literal
let types = HashMap::new();
let module_id = "".into();
@ -2972,6 +2945,10 @@ mod tests {
#[test]
fn element_type_mismatch() {
// having different types in an array isn't allowed
// in the case of arrays, lengths do *not* have to match, as at this point they can be
// generic, so we cannot tell yet
let types = HashMap::new();
let module_id = "".into();
// [3, true]
@ -3095,15 +3072,47 @@ mod tests {
let mut unifier = SymbolUnifier::default();
// the `foo` type
assert!(unifier.insert_type("foo"));
// the `foo` type annot be declared a second time
assert!(!unifier.insert_type("foo"));
// the `foo` function cannot be declared as the name is already taken by a type
assert!(!unifier.insert_function("foo", DeclarationSignature::new()));
// the `bar` type
assert!(unifier.insert_function("bar", DeclarationSignature::new()));
// a second `bar` function of the same signature cannot be declared
assert!(!unifier.insert_function("bar", DeclarationSignature::new()));
// a second `bar` function of a different signature can be declared
assert!(unifier.insert_function(
"bar",
DeclarationSignature::new().inputs(vec![DeclarationType::FieldElement])
));
// a second `bar` function with a generic parameter, which *could* conflict with an existing one should not be allowed
assert!(!unifier.insert_function(
"bar",
DeclarationSignature::new()
.generics(vec![Some("K".into())])
.inputs(vec![DeclarationType::FieldElement])
));
// a `bar` function with a different signature
assert!(unifier.insert_function(
"bar",
DeclarationSignature::new()
.generics(vec![Some("K".into())])
.inputs(vec![DeclarationType::array((
DeclarationType::FieldElement,
"K"
))])
));
// a `bar` function with a different signature, but which could conflict with the previous one
assert!(!unifier.insert_function(
"bar",
DeclarationSignature::new().inputs(vec![DeclarationType::array((
DeclarationType::FieldElement,
42u32
))])
));
// a `bar` type isn't allowed as the name is already taken by at least one function
assert!(!unifier.insert_type("bar"));
}
@ -3646,6 +3655,66 @@ mod tests {
}
}
// checking function signatures
mod signature {
use super::*;
#[test]
fn undeclared_generic() {
let signature = UnresolvedSignature::new().inputs(vec![UnresolvedType::Array(
box UnresolvedType::FieldElement.mock(),
Expression::Identifier("K").mock(),
)
.mock()]);
assert_eq!(Checker::<Bn128Field>::new().check_signature(signature, &MODULE_ID.into(), &TypeMap::default()), Err(vec![ErrorInner {
pos: Some((Position::mock(), Position::mock())),
message: "Undeclared generic parameter in function definition: `K` isn\'t declared as a generic constant".to_string()
}]));
}
#[test]
fn success() {
// <K, L, M>(field[L][K]) -> field[L][K]
let signature = UnresolvedSignature::new()
.generics(vec!["K".mock(), "L".mock(), "M".mock()])
.inputs(vec![UnresolvedType::Array(
box UnresolvedType::Array(
box UnresolvedType::FieldElement.mock(),
Expression::Identifier("K").mock(),
)
.mock(),
Expression::Identifier("L").mock(),
)
.mock()])
.outputs(vec![UnresolvedType::Array(
box UnresolvedType::Array(
box UnresolvedType::FieldElement.mock(),
Expression::Identifier("L").mock(),
)
.mock(),
Expression::Identifier("K").mock(),
)
.mock()]);
assert_eq!(
Checker::<Bn128Field>::new().check_signature(
signature,
&MODULE_ID.into(),
&TypeMap::default()
),
Ok(DeclarationSignature::new()
.inputs(vec![DeclarationType::array((
DeclarationType::array((DeclarationType::FieldElement, "K")),
"L"
))])
.outputs(vec![DeclarationType::array((
DeclarationType::array((DeclarationType::FieldElement, "L")),
"K"
))]))
);
}
}
#[test]
fn undefined_variable_in_statement() {
// a = b
@ -5191,127 +5260,6 @@ mod tests {
"Undefined type Bar"
);
}
#[test]
fn parameter() {
// a defined type can be used as parameter
// an undefined type cannot be used as parameter
let (mut checker, state) = create_module_with_foo(StructDefinition {
fields: vec![StructDefinitionField {
id: "foo",
ty: UnresolvedType::FieldElement.mock(),
}
.mock()],
});
assert_eq!(
checker.check_parameter(
absy::Parameter {
id:
absy::Variable::new("a", UnresolvedType::User("Foo".into()).mock(),)
.mock(),
private: true,
}
.mock(),
&PathBuf::from(MODULE_ID),
&state.types,
&HashSet::new()
),
Ok(DeclarationParameter {
id: DeclarationVariable::with_id_and_type(
"a",
DeclarationType::Struct(DeclarationStructType::new(
"".into(),
"Foo".into(),
vec![DeclarationStructMember::new(
"foo".into(),
DeclarationType::FieldElement
)]
))
),
private: true
})
);
assert_eq!(
checker
.check_parameter(
absy::Parameter {
id: absy::Variable::new(
"a",
UnresolvedType::User("Bar".into()).mock(),
)
.mock(),
private: true,
}
.mock(),
&PathBuf::from(MODULE_ID),
&state.types,
&HashSet::new()
)
.unwrap_err()[0]
.message,
"Undefined type Bar"
);
}
#[test]
fn variable_declaration() {
// a defined type can be used in a variable declaration
// an undefined type cannot be used in a variable declaration
let (mut checker, state) = create_module_with_foo(StructDefinition {
fields: vec![StructDefinitionField {
id: "foo",
ty: UnresolvedType::FieldElement.mock(),
}
.mock()],
});
assert_eq!(
checker.check_statement(
Statement::Declaration(
absy::Variable::new("a", UnresolvedType::User("Foo".into()).mock(),)
.mock()
)
.mock(),
&PathBuf::from(MODULE_ID),
&state.types,
),
Ok(TypedStatement::Declaration(Variable::with_id_and_type(
"a",
Type::Struct(StructType::new(
"".into(),
"Foo".into(),
vec![StructMember::new("foo".into(), Type::FieldElement)]
))
)))
);
assert_eq!(
checker
.check_parameter(
absy::Parameter {
id: absy::Variable::new(
"a",
UnresolvedType::User("Bar".into()).mock(),
)
.mock(),
private: true,
}
.mock(),
&PathBuf::from(MODULE_ID),
&state.types,
&HashSet::new()
)
.unwrap_err()[0]
.message,
"Undefined type Bar"
);
}
}
/// tests about accessing members

View file

@ -29,8 +29,6 @@ use crate::typed_absy::types::ConcreteGenericsAssignment;
use crate::typed_absy::types::Type;
use crate::typed_absy::*;
use std::collections::HashSet;
use zokrates_field::Field;
use super::{Output, Versions};
@ -266,172 +264,6 @@ mod tests {
mod normal {
use super::*;
// #[test]
// fn ssa_array() {
// let a0 =
// ArrayExpressionInner::Identifier("a".into()).annotate(Type::FieldElement, 3u32);
// let e = FieldElementExpression::Number(Bn128Field::from(42)).into();
// let index = 1u32.into();
// let a1 = choose_many(
// a0.clone().into(),
// vec![Access::Select(index)],
// e,
// &mut HashSet::new(),
// );
// // a[1] = 42
// // -> a = [0 == 1 ? 42 : a[0], 1 == 1 ? 42 : a[1], 2 == 1 ? 42 : a[2]]
// assert_eq!(
// a1,
// ArrayExpressionInner::Value(vec![
// FieldElementExpression::if_else(
// BooleanExpression::UintEq(box 0u32.into(), box 1u32.into()),
// FieldElementExpression::Number(Bn128Field::from(42)),
// FieldElementExpression::select(a0.clone(), 0u32)
// )
// .into(),
// FieldElementExpression::if_else(
// BooleanExpression::UintEq(box 1u32.into(), box 1u32.into()),
// FieldElementExpression::Number(Bn128Field::from(42)),
// FieldElementExpression::select(a0.clone(), 1u32)
// )
// .into(),
// FieldElementExpression::if_else(
// BooleanExpression::UintEq(box 2u32.into(), box 1u32.into()),
// FieldElementExpression::Number(Bn128Field::from(42)),
// FieldElementExpression::select(a0.clone(), 2u32)
// )
// .into()
// ])
// .annotate(Type::FieldElement, 3u32)
// .into()
// );
// let a0: ArrayExpression<Bn128Field> = ArrayExpressionInner::Identifier("a".into())
// .annotate(Type::array(Type::FieldElement, 3u32), 3u32);
// let e = ArrayExpressionInner::Identifier("b".into()).annotate(Type::FieldElement, 3u32);
// let index = 1u32.into();
// let a1 = choose_many(
// a0.clone().into(),
// vec![Access::Select(index)],
// e.clone().into(),
// &mut HashSet::new(),
// );
// // a[0] = b
// // -> a = [0 == 1 ? b : a[0], 1 == 1 ? b : a[1], 2 == 1 ? b : a[2]]
// assert_eq!(
// a1,
// ArrayExpressionInner::Value(vec![
// ArrayExpression::if_else(
// BooleanExpression::UintEq(box 0u32.into(), box 1u32.into()),
// e.clone(),
// ArrayExpression::select(a0.clone(), 0u32)
// )
// .into(),
// ArrayExpression::if_else(
// BooleanExpression::UintEq(box 1u32.into(), box 1u32.into()),
// e.clone(),
// ArrayExpression::select(a0.clone(), 1u32)
// )
// .into(),
// ArrayExpression::if_else(
// BooleanExpression::UintEq(box 2u32.into(), box 1u32.into()),
// e.clone(),
// ArrayExpression::select(a0.clone(), 2u32)
// )
// .into()
// ])
// .annotate(Type::array(Type::FieldElement, 3u32), 3u32)
// .into()
// );
// let a0 = ArrayExpressionInner::Identifier("a".into())
// .annotate(Type::array(Type::FieldElement, 2u32), 2u32);
// let e = FieldElementExpression::Number(Bn128Field::from(42));
// let indices = vec![Access::Select(0u32.into()), Access::Select(0u32.into())];
// let a1 = choose_many(
// a0.clone().into(),
// indices,
// e.clone().into(),
// &mut HashSet::new(),
// );
// // a[0][0] = 42
// // -> a = [0 == 0 ? [0 == 0 ? 42 : a[0][0], 1 == 0 ? 42 : a[0][1]] : a[0], 1 == 0 ? [0 == 0 ? 42 : a[1][0], 1 == 0 ? 42 : a[1][1]] : a[1]]
// assert_eq!(
// a1,
// ArrayExpressionInner::Value(vec![
// ArrayExpression::if_else(
// BooleanExpression::UintEq(box 0u32.into(), box 0u32.into()),
// ArrayExpressionInner::Value(vec![
// FieldElementExpression::if_else(
// BooleanExpression::UintEq(box 0u32.into(), box 0u32.into()),
// e.clone(),
// FieldElementExpression::select(
// ArrayExpression::select(a0.clone(), 0u32),
// 0u32
// )
// )
// .into(),
// FieldElementExpression::if_else(
// BooleanExpression::UintEq(box 1u32.into(), box 0u32.into()),
// e.clone(),
// FieldElementExpression::select(
// ArrayExpression::select(a0.clone(), 0u32),
// 1u32
// )
// )
// .into()
// ])
// .annotate(Type::FieldElement, 2u32),
// ArrayExpression::select(a0.clone(), 0u32)
// )
// .into(),
// ArrayExpression::if_else(
// BooleanExpression::UintEq(box 1u32.into(), box 0u32.into()),
// ArrayExpressionInner::Value(vec![
// FieldElementExpression::if_else(
// BooleanExpression::UintEq(box 0u32.into(), box 0u32.into()),
// e.clone(),
// FieldElementExpression::select(
// ArrayExpression::select(a0.clone(), 1u32),
// 0u32
// )
// )
// .into(),
// FieldElementExpression::if_else(
// BooleanExpression::UintEq(box 1u32.into(), box 0u32.into()),
// e.clone(),
// FieldElementExpression::select(
// ArrayExpression::select(a0.clone(), 1u32),
// 1u32
// )
// )
// .into()
// ])
// .annotate(Type::FieldElement, 2u32),
// ArrayExpression::select(a0.clone(), 1u32)
// )
// .into(),
// ])
// .annotate(Type::array(Type::FieldElement, 2u32), 2u32)
// .into()
// );
// }
#[test]
fn detect_non_constant_bound() {
let loops: Vec<TypedStatement<Bn128Field>> = vec![TypedStatement::For(

View file

@ -150,7 +150,7 @@ mod tests {
access(7, 15, [
call_access(7, 15, [
explicit_generics(7, 12, [
identifier_or_underscore(10, 11, [
constant_generics_values(10, 11, [
underscore(10, 11)
])
]),

View file

@ -72,8 +72,8 @@ array_access = { "[" ~ range_or_expression ~ "]" }
call_access = { explicit_generics? ~ "(" ~ arguments ~ ")" }
arguments = { expression_list }
explicit_generics = { "::<" ~ constant_generics_values ~ ">" }
constant_generics_values = _{ identifier_or_underscore ~ ("," ~ identifier_or_underscore)* }
identifier_or_underscore = { identifier | underscore }
constant_generics_values = _{ constant_generic_value ~ ("," ~ constant_generic_value)* }
constant_generic_value = { literal | identifier | underscore }
underscore = { "_" }
member_access = { "." ~ identifier }

View file

@ -10,12 +10,12 @@ extern crate lazy_static;
pub use ast::{
Access, Arguments, ArrayAccess, ArrayInitializerExpression, ArrayType, AssertionStatement,
Assignee, AssigneeAccess, BasicOrStructType, BasicType, BinaryExpression, BinaryOperator,
CallAccess, DecimalLiteralExpression, DecimalNumber, DecimalSuffix, DefinitionStatement,
ExplicitGenerics, Expression, FieldType, File, FromExpression, Function, HexLiteralExpression,
HexNumberExpression, IdentifierExpression, IdentifierExpressionOrUnderscore, ImportDirective,
ImportSource, InlineArrayExpression, InlineStructExpression, InlineStructMember,
IterationStatement, LiteralExpression, OptionallyTypedAssignee, Parameter, PostfixExpression,
Range, RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression, Statement,
CallAccess, ConstantGenericValue, DecimalLiteralExpression, DecimalNumber, DecimalSuffix,
DefinitionStatement, ExplicitGenerics, Expression, FieldType, File, FromExpression, Function,
HexLiteralExpression, HexNumberExpression, IdentifierExpression, ImportDirective, ImportSource,
InlineArrayExpression, InlineStructExpression, InlineStructMember, IterationStatement,
LiteralExpression, OptionallyTypedAssignee, Parameter, PostfixExpression, Range,
RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression, Statement,
StructDefinition, StructField, TernaryExpression, ToExpression, Type, UnaryExpression,
UnaryOperator, Underscore, Visibility,
};
@ -590,14 +590,15 @@ mod ast {
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::explicit_generics))]
pub struct ExplicitGenerics<'ast> {
pub identifiers_or_underscores: Vec<IdentifierExpressionOrUnderscore<'ast>>,
pub values: Vec<ConstantGenericValue<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::identifier_or_underscore))]
pub enum IdentifierExpressionOrUnderscore<'ast> {
#[pest_ast(rule(Rule::constant_generic_value))]
pub enum ConstantGenericValue<'ast> {
Value(LiteralExpression<'ast>),
Identifier(IdentifierExpression<'ast>),
Underscore(Underscore<'ast>),
}