mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-29 11:43:28 +03:00
enforce explicit types in defnitions and arrays
This commit is contained in:
parent
9e163428a9
commit
59cf617a08
@ -1,10 +1,8 @@
|
||||
function test() -> (u32, u32) {
|
||||
return 4, 4
|
||||
}
|
||||
|
||||
function main() -> (u32, u32) {
|
||||
a, b = test()
|
||||
|
||||
return a, b
|
||||
function main() -> (u32[3]) {
|
||||
a = [1, 2]
|
||||
c = 3
|
||||
u32[3] b = [...a, c]
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Methods to enforce constraints a resolved aleo program.
|
||||
//! Methods to enforce constraints and construct a resolved aleo program.
|
||||
|
||||
use crate::ast;
|
||||
use crate::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
||||
@ -98,13 +98,26 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function.returns.to_owned(),
|
||||
)
|
||||
}
|
||||
Statement::MultipleDefinition(assignees, function_call) => self
|
||||
.enforce_multiple_definition_statement(
|
||||
Statement::Assign(variable, expression) => {
|
||||
self.enforce_assign_statement(cs, function.get_name(), variable, expression);
|
||||
}
|
||||
Statement::Definition(ty, assignee, expression) => {
|
||||
self.enforce_definition_statement(
|
||||
cs,
|
||||
function.get_name(),
|
||||
ty,
|
||||
assignee,
|
||||
expression,
|
||||
);
|
||||
}
|
||||
Statement::MultipleDefinition(assignees, function_call) => {
|
||||
self.enforce_multiple_definition_statement(
|
||||
cs,
|
||||
function.get_name(),
|
||||
assignees,
|
||||
function_call,
|
||||
),
|
||||
);
|
||||
}
|
||||
Statement::For(index, start, stop, statements) => {
|
||||
self.enforce_for_statement(
|
||||
cs,
|
||||
@ -115,14 +128,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
statements,
|
||||
);
|
||||
}
|
||||
Statement::Definition(variable, expression) => {
|
||||
self.enforce_definition_statement(
|
||||
cs,
|
||||
function.get_name(),
|
||||
variable,
|
||||
expression,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return_values
|
||||
@ -140,9 +145,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
.for_each(|(i, parameter)| {
|
||||
// append each variable to arguments vector
|
||||
arguments.push(Expression::Variable(match parameter.ty {
|
||||
Type::U32 => {
|
||||
self.integer_from_parameter(cs, function.get_name(), i + 1, parameter)
|
||||
}
|
||||
Type::U32 => self.u32_from_parameter(cs, function.get_name(), i + 1, parameter),
|
||||
Type::FieldElement => {
|
||||
self.field_element_from_parameter(cs, function.get_name(), i + 1, parameter)
|
||||
}
|
||||
@ -150,12 +153,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
self.bool_from_parameter(cs, function.get_name(), i + 1, parameter)
|
||||
}
|
||||
Type::Array(ref ty, _length) => match *ty.clone() {
|
||||
Type::U32 => self.integer_array_from_parameter(
|
||||
cs,
|
||||
function.get_name(),
|
||||
i + 1,
|
||||
parameter,
|
||||
),
|
||||
Type::U32 => {
|
||||
self.u32_array_from_parameter(cs, function.get_name(), i + 1, parameter)
|
||||
}
|
||||
Type::FieldElement => self.field_element_array_from_parameter(
|
||||
cs,
|
||||
function.get_name(),
|
||||
|
@ -10,7 +10,7 @@ use snarkos_models::gadgets::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
pub(crate) fn integer_from_parameter(
|
||||
pub(crate) fn u32_from_parameter(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
@ -46,7 +46,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn integer_array_from_parameter(
|
||||
pub(crate) fn u32_array_from_parameter(
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
_scope: String,
|
||||
|
@ -27,7 +27,15 @@ impl<F: Field + PrimeField> ResolvedValue<F> {
|
||||
(ResolvedValue::U32(ref _a), Type::U32) => true,
|
||||
(ResolvedValue::FieldElement(ref _a), Type::FieldElement) => true,
|
||||
(ResolvedValue::Boolean(ref _a), Type::Boolean) => true,
|
||||
(ResolvedValue::Array(ref arr), Type::Array(ref _ty, ref len)) => arr.len() == *len, // todo: add array types
|
||||
(ResolvedValue::Array(ref arr), Type::Array(ref ty, ref len)) => {
|
||||
// check array lengths are equal
|
||||
let mut res = arr.len() == *len;
|
||||
// check each value in array matches
|
||||
for value in arr {
|
||||
res &= value.match_type(ty)
|
||||
}
|
||||
res
|
||||
}
|
||||
(
|
||||
ResolvedValue::StructExpression(ref actual_name, ref _members),
|
||||
Type::Struct(ref expected_name),
|
||||
|
@ -17,7 +17,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_definition(
|
||||
fn store_assignment(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
@ -117,7 +117,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_definition_statement(
|
||||
pub(crate) fn enforce_assign_statement(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
@ -126,7 +126,24 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
) {
|
||||
let result_value = &mut self.enforce_expression(cs, scope.clone(), expression);
|
||||
|
||||
self.enforce_definition(cs, scope, assignee, result_value);
|
||||
self.store_assignment(cs, scope, assignee, result_value);
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_definition_statement(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
ty: Type<F>,
|
||||
assignee: Assignee<F>,
|
||||
expression: Expression<F>,
|
||||
) {
|
||||
let result_value = &mut self.enforce_expression(cs, scope.clone(), expression);
|
||||
|
||||
if result_value.match_type(&ty) {
|
||||
self.store_assignment(cs, scope, assignee, result_value);
|
||||
} else {
|
||||
unimplemented!("incompatible types {} = {}", assignee, result_value)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_multiple_definition_statement(
|
||||
@ -149,7 +166,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
.into_iter()
|
||||
.zip(return_values.into_iter())
|
||||
.for_each(|(assignee, mut return_value)| {
|
||||
self.enforce_definition(cs, scope.clone(), assignee, &mut return_value);
|
||||
self.store_assignment(cs, scope.clone(), assignee, &mut return_value);
|
||||
});
|
||||
}
|
||||
|
||||
@ -188,14 +205,17 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// TODO: add support for early termination
|
||||
let _res = self.enforce_return_statement(cs, scope, statements, return_types);
|
||||
}
|
||||
Statement::For(index, start, stop, statements) => {
|
||||
self.enforce_for_statement(cs, scope, index, start, stop, statements);
|
||||
Statement::Assign(variable, expression) => {
|
||||
self.enforce_assign_statement(cs, scope, variable, expression);
|
||||
}
|
||||
Statement::Definition(ty, assignee, expression) => {
|
||||
self.enforce_definition_statement(cs, scope, ty, assignee, expression);
|
||||
}
|
||||
Statement::MultipleDefinition(assignees, function) => {
|
||||
self.enforce_multiple_definition_statement(cs, scope, assignees, function);
|
||||
}
|
||||
Statement::Definition(variable, expression) => {
|
||||
self.enforce_definition_statement(cs, scope, variable, expression);
|
||||
Statement::For(index, start, stop, statements) => {
|
||||
self.enforce_for_statement(cs, scope, index, start, stop, statements);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -97,17 +97,7 @@ pub enum Assignee<F: Field + PrimeField> {
|
||||
StructMember(Box<Assignee<F>>, Variable<F>),
|
||||
}
|
||||
|
||||
/// Program statement that defines some action (or expression) to be carried out.
|
||||
#[derive(Clone)]
|
||||
pub enum Statement<F: Field + PrimeField> {
|
||||
// Declaration(Variable),
|
||||
Return(Vec<Expression<F>>),
|
||||
Definition(Assignee<F>, Expression<F>),
|
||||
For(Variable<F>, Integer, Integer, Vec<Statement<F>>),
|
||||
MultipleDefinition(Vec<Assignee<F>>, Expression<F>),
|
||||
}
|
||||
|
||||
/// Explicit type used for defining struct members and function parameters
|
||||
/// Explicit type used for defining a variable or expression type
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Type<F: Field + PrimeField> {
|
||||
U32,
|
||||
@ -117,6 +107,17 @@ pub enum Type<F: Field + PrimeField> {
|
||||
Struct(Variable<F>),
|
||||
}
|
||||
|
||||
/// Program statement that defines some action (or expression) to be carried out.
|
||||
#[derive(Clone)]
|
||||
pub enum Statement<F: Field + PrimeField> {
|
||||
// Declaration(Variable),
|
||||
Return(Vec<Expression<F>>),
|
||||
Assign(Assignee<F>, Expression<F>),
|
||||
Definition(Type<F>, Assignee<F>, Expression<F>),
|
||||
MultipleDefinition(Vec<Assignee<F>>, Expression<F>),
|
||||
For(Variable<F>, Integer, Integer, Vec<Statement<F>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StructMember<F: Field + PrimeField> {
|
||||
pub variable: Variable<F>,
|
||||
|
@ -151,6 +151,12 @@ impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
||||
}
|
||||
write!(f, "\n")
|
||||
}
|
||||
Statement::Assign(ref variable, ref statement) => {
|
||||
write!(f, "{} = {}", variable, statement)
|
||||
}
|
||||
Statement::Definition(ref ty, ref assignee, ref statement) => {
|
||||
write!(f, "{} {} = {}", ty, assignee, statement)
|
||||
}
|
||||
Statement::MultipleDefinition(ref assignees, ref function) => {
|
||||
for (i, id) in assignees.iter().enumerate() {
|
||||
write!(f, "{}", id)?;
|
||||
@ -167,9 +173,6 @@ impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
||||
}
|
||||
write!(f, "\tendfor")
|
||||
}
|
||||
Statement::Definition(ref variable, ref statement) => {
|
||||
write!(f, "{} = {}", variable, statement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,6 +190,12 @@ impl<F: Field + PrimeField> fmt::Debug for Statement<F> {
|
||||
}
|
||||
write!(f, "\n")
|
||||
}
|
||||
Statement::Assign(ref variable, ref statement) => {
|
||||
write!(f, "{} = {}", variable, statement)
|
||||
}
|
||||
Statement::Definition(ref ty, ref assignee, ref statement) => {
|
||||
write!(f, "{} {} = {}", ty, assignee, statement)
|
||||
}
|
||||
Statement::MultipleDefinition(ref assignees, ref function) => {
|
||||
for (i, id) in assignees.iter().enumerate() {
|
||||
write!(f, "{}", id)?;
|
||||
@ -203,9 +212,6 @@ impl<F: Field + PrimeField> fmt::Debug for Statement<F> {
|
||||
}
|
||||
write!(f, "\tendfor")
|
||||
}
|
||||
Statement::Definition(ref variable, ref statement) => {
|
||||
write!(f, "{} = {}", variable, statement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,6 +192,50 @@ impl<'ast, F: Field + PrimeField> From<ast::TernaryExpression<'ast>> for types::
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::ArrayInlineExpression<'ast>> for types::Expression<F> {
|
||||
fn from(array: ast::ArrayInlineExpression<'ast>) -> Self {
|
||||
types::Expression::Array(
|
||||
array
|
||||
.expressions
|
||||
.into_iter()
|
||||
.map(|s_or_e| Box::new(types::SpreadOrExpression::from(s_or_e)))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<'ast, F: Field + PrimeField> From<ast::ArrayInitializerExpression<'ast>>
|
||||
for types::Expression<F>
|
||||
{
|
||||
fn from(array: ast::ArrayInitializerExpression<'ast>) -> Self {
|
||||
let count = types::Expression::<F>::get_count(array.count);
|
||||
let expression = Box::new(types::SpreadOrExpression::from(*array.expression));
|
||||
|
||||
types::Expression::Array(vec![expression; count])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::InlineStructMember<'ast>> for types::StructMember<F> {
|
||||
fn from(member: ast::InlineStructMember<'ast>) -> Self {
|
||||
types::StructMember {
|
||||
variable: types::Variable::from(member.variable),
|
||||
expression: types::Expression::from(member.expression),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::StructInlineExpression<'ast>> for types::Expression<F> {
|
||||
fn from(expression: ast::StructInlineExpression<'ast>) -> Self {
|
||||
let variable = types::Variable::from(expression.variable);
|
||||
let members = expression
|
||||
.members
|
||||
.into_iter()
|
||||
.map(|member| types::StructMember::from(member))
|
||||
.collect::<Vec<types::StructMember<F>>>();
|
||||
|
||||
types::Expression::Struct(variable, members)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::PostfixExpression<'ast>> for types::Expression<F> {
|
||||
fn from(expression: ast::PostfixExpression<'ast>) -> Self {
|
||||
let variable = types::Expression::Variable(types::Variable::from(expression.variable));
|
||||
@ -229,28 +273,6 @@ impl<'ast, F: Field + PrimeField> From<ast::PostfixExpression<'ast>> for types::
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::ArrayInlineExpression<'ast>> for types::Expression<F> {
|
||||
fn from(array: ast::ArrayInlineExpression<'ast>) -> Self {
|
||||
types::Expression::Array(
|
||||
array
|
||||
.expressions
|
||||
.into_iter()
|
||||
.map(|s_or_e| Box::new(types::SpreadOrExpression::from(s_or_e)))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<'ast, F: Field + PrimeField> From<ast::ArrayInitializerExpression<'ast>>
|
||||
for types::Expression<F>
|
||||
{
|
||||
fn from(array: ast::ArrayInitializerExpression<'ast>) -> Self {
|
||||
let count = types::Expression::<F>::get_count(array.count);
|
||||
let expression = Box::new(types::SpreadOrExpression::from(*array.expression));
|
||||
|
||||
types::Expression::Array(vec![expression; count])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::Expression<'ast>> for types::Expression<F> {
|
||||
fn from(expression: ast::Expression<'ast>) -> Self {
|
||||
match expression {
|
||||
@ -261,18 +283,13 @@ impl<'ast, F: Field + PrimeField> From<ast::Expression<'ast>> for types::Express
|
||||
ast::Expression::Ternary(expression) => types::Expression::from(expression),
|
||||
ast::Expression::ArrayInline(expression) => types::Expression::from(expression),
|
||||
ast::Expression::ArrayInitializer(expression) => types::Expression::from(expression),
|
||||
ast::Expression::StructInline(_expression) => {
|
||||
unimplemented!("unknown type for inline struct expression")
|
||||
}
|
||||
ast::Expression::StructInline(expression) => types::Expression::from(expression),
|
||||
ast::Expression::Postfix(expression) => types::Expression::from(expression),
|
||||
// _ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// pest ast -> typed types::Expression
|
||||
/// For defined types (ex: u32[4]) we manually construct the expression instead of implementing the From trait.
|
||||
/// This saves us from having to resolve things at a later point in time.
|
||||
impl<'ast, F: Field + PrimeField> types::Expression<F> {
|
||||
fn get_count(count: ast::Value<'ast>) -> usize {
|
||||
match count {
|
||||
@ -284,34 +301,6 @@ impl<'ast, F: Field + PrimeField> types::Expression<F> {
|
||||
size => unimplemented!("Array size should be an integer {}", size),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_struct(ty: ast::StructType<'ast>, expression: ast::Expression<'ast>) -> Self {
|
||||
let declaration_struct = ty.variable.value;
|
||||
match expression {
|
||||
ast::Expression::StructInline(inline_struct) => {
|
||||
if inline_struct.variable.value != declaration_struct {
|
||||
unimplemented!("Declared struct type must match inline struct type")
|
||||
}
|
||||
let variable = types::Variable::from(inline_struct.variable);
|
||||
let members = inline_struct
|
||||
.members
|
||||
.into_iter()
|
||||
.map(|member| types::StructMember::from(member))
|
||||
.collect::<Vec<types::StructMember<F>>>();
|
||||
|
||||
types::Expression::Struct(variable, members)
|
||||
}
|
||||
_ => unimplemented!("Struct declaration must be followed by inline struct"),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_type(ty: ast::Type<'ast>, expression: ast::Expression<'ast>) -> Self {
|
||||
match ty {
|
||||
ast::Type::Basic(_ty) => Self::from(expression),
|
||||
ast::Type::Array(_ty) => Self::from(expression),
|
||||
ast::Type::Struct(ty) => Self::from_struct(ty, expression),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// pest ast -> types::Assignee
|
||||
@ -407,7 +396,7 @@ impl<'ast, F: Field + PrimeField> From<ast::MultipleAssignmentStatement<'ast>>
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::AssignStatement<'ast>> for types::Statement<F> {
|
||||
fn from(statement: ast::AssignStatement<'ast>) -> Self {
|
||||
types::Statement::Definition(
|
||||
types::Statement::Assign(
|
||||
types::Assignee::from(statement.assignee),
|
||||
types::Expression::from(statement.expression),
|
||||
)
|
||||
@ -417,8 +406,9 @@ impl<'ast, F: Field + PrimeField> From<ast::AssignStatement<'ast>> for types::St
|
||||
impl<'ast, F: Field + PrimeField> From<ast::DefinitionStatement<'ast>> for types::Statement<F> {
|
||||
fn from(statement: ast::DefinitionStatement<'ast>) -> Self {
|
||||
types::Statement::Definition(
|
||||
types::Type::from(statement.ty),
|
||||
types::Assignee::from(statement.variable),
|
||||
types::Expression::from_type(statement.ty, statement.expression),
|
||||
types::Expression::from(statement.expression),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -474,15 +464,6 @@ impl<'ast, F: Field + PrimeField> From<ast::Type<'ast>> for types::Type<F> {
|
||||
|
||||
/// pest ast -> types::Struct
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::InlineStructMember<'ast>> for types::StructMember<F> {
|
||||
fn from(member: ast::InlineStructMember<'ast>) -> Self {
|
||||
types::StructMember {
|
||||
variable: types::Variable::from(member.variable),
|
||||
expression: types::Expression::from(member.expression),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::StructField<'ast>> for types::StructField<F> {
|
||||
fn from(struct_field: ast::StructField<'ast>) -> Self {
|
||||
types::StructField {
|
||||
|
Loading…
Reference in New Issue
Block a user