diff --git a/benchmark/simple.leo b/benchmark/simple.leo index 266e1c725d..88b04004df 100644 --- a/benchmark/simple.leo +++ b/benchmark/simple.leo @@ -1,5 +1,3 @@ function main() { let g: group = 123456789; - - } \ No newline at end of file diff --git a/compiler/src/constraints/expression.rs b/compiler/src/constraints/expression.rs index cc941b50bf..95d0aae2ba 100644 --- a/compiler/src/constraints/expression.rs +++ b/compiler/src/constraints/expression.rs @@ -1,16 +1,11 @@ //! Methods to enforce constraints on expressions in a resolved Leo program. -use crate::{ - constraints::{ - new_scope_from_variable, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, - }, - errors::ExpressionError, - new_scope, - types::{ - CircuitFieldDefinition, CircuitMember, Expression, Identifier, RangeOrExpression, - SpreadOrExpression, - }, -}; +use crate::{constraints::{ + new_scope_from_variable, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, +}, errors::ExpressionError, new_scope, types::{ + CircuitFieldDefinition, CircuitMember, Expression, Identifier, RangeOrExpression, + SpreadOrExpression, +}, Type}; use snarkos_models::{ curves::{Field, Group, PrimeField}, @@ -312,6 +307,7 @@ impl> ConstrainedProgra cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, array: Vec>>, ) -> Result, ExpressionError> { let mut result = vec![]; @@ -337,6 +333,7 @@ impl> ConstrainedProgra cs, file_scope.clone(), function_scope.clone(), + expected_types.clone(), expression, )?); } @@ -350,9 +347,10 @@ impl> ConstrainedProgra cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, index: Expression, ) -> Result { - match self.enforce_expression(cs, file_scope, function_scope, index)? { + match self.enforce_expression(cs, file_scope, function_scope, expected_types, index)? { ConstrainedValue::Integer(number) => Ok(number.to_usize()), value => Err(ExpressionError::InvalidIndex(value.to_string())), } @@ -363,6 +361,7 @@ impl> ConstrainedProgra cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, array: Box>, index: RangeOrExpression, ) -> Result, ExpressionError> { @@ -370,6 +369,7 @@ impl> ConstrainedProgra cs, file_scope.clone(), function_scope.clone(), + expected_types.clone(), *array, )? { ConstrainedValue::Array(array) => array, @@ -395,7 +395,7 @@ impl> ConstrainedProgra )) } RangeOrExpression::Expression(index) => { - let index_resolved = self.enforce_index(cs, file_scope, function_scope, index)?; + let index_resolved = self.enforce_index(cs, file_scope, function_scope, expected_types, index)?; Ok(array[index_resolved].to_owned()) } } @@ -406,6 +406,7 @@ impl> ConstrainedProgra cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, identifier: Identifier, members: Vec>, ) -> Result, ExpressionError> { @@ -434,6 +435,7 @@ impl> ConstrainedProgra cs, file_scope.clone(), function_scope.clone(), + expected_types.clone(), field.expression, )?; @@ -482,6 +484,7 @@ impl> ConstrainedProgra cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, circuit_identifier: Box>, circuit_member: Identifier, ) -> Result, ExpressionError> { @@ -489,6 +492,7 @@ impl> ConstrainedProgra cs, file_scope.clone(), function_scope.clone(), + expected_types.clone(), *circuit_identifier.clone(), )? { ConstrainedValue::CircuitExpression(name, members) => (name, members), @@ -541,6 +545,7 @@ impl> ConstrainedProgra cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, circuit_identifier: Box>, circuit_member: Identifier, ) -> Result, ExpressionError> { @@ -549,6 +554,7 @@ impl> ConstrainedProgra cs, file_scope.clone(), function_scope.clone(), + expected_types.clone(), *circuit_identifier.clone(), )? { ConstrainedValue::CircuitDefinition(circuit_definition) => circuit_definition, @@ -591,6 +597,7 @@ impl> ConstrainedProgra cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, function: Box>, arguments: Vec>, ) -> Result, ExpressionError> { @@ -598,6 +605,7 @@ impl> ConstrainedProgra cs, file_scope.clone(), function_scope.clone(), + expected_types.clone(), *function.clone(), )?; @@ -627,11 +635,25 @@ impl> ConstrainedProgra } } + pub(crate) fn enforce_number_implicit( + expected_types: Vec>, + value: String, + ) -> Result, ExpressionError> { + if expected_types.len() != 1 { + return Err(ExpressionError::SingleType(value)) + } + + Ok(ConstrainedValue::from_type(value, &expected_types[0])?) + + + } + pub(crate) fn enforce_expression( &mut self, cs: &mut CS, file_scope: String, function_scope: String, + expected_types: Vec>, expression: Expression, ) -> Result, ExpressionError> { match expression { @@ -645,16 +667,17 @@ impl> ConstrainedProgra Expression::FieldElement(fe) => Ok(Self::get_field_element_constant(fe)), Expression::GroupElement(gr) => Ok(ConstrainedValue::GroupElement(gr)), Expression::Boolean(bool) => Ok(Self::get_boolean_constant(bool)), - Expression::Implicit(string) => unimplemented!(), + Expression::Implicit(value) => Self::enforce_number_implicit(expected_types, value), // Binary operations Expression::Add(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -662,11 +685,12 @@ impl> ConstrainedProgra } Expression::Sub(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -674,11 +698,12 @@ impl> ConstrainedProgra } Expression::Mul(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -686,11 +711,12 @@ impl> ConstrainedProgra } Expression::Div(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -698,11 +724,12 @@ impl> ConstrainedProgra } Expression::Pow(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -714,15 +741,17 @@ impl> ConstrainedProgra cs, file_scope, function_scope, + expected_types, *expression, )?)?), Expression::Or(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -730,11 +759,12 @@ impl> ConstrainedProgra } Expression::And(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -742,11 +772,12 @@ impl> ConstrainedProgra } Expression::Eq(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -754,11 +785,12 @@ impl> ConstrainedProgra } Expression::Geq(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -766,11 +798,12 @@ impl> ConstrainedProgra } Expression::Gt(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -778,11 +811,12 @@ impl> ConstrainedProgra } Expression::Leq(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -790,11 +824,12 @@ impl> ConstrainedProgra } Expression::Lt(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types.clone(), *left)?; let resolved_right = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, *right, )?; @@ -807,6 +842,7 @@ impl> ConstrainedProgra cs, file_scope.clone(), function_scope.clone(), + expected_types.clone(), *first, )? { ConstrainedValue::Boolean(resolved) => resolved, @@ -814,18 +850,18 @@ impl> ConstrainedProgra }; if resolved_first.eq(&Boolean::Constant(true)) { - self.enforce_expression(cs, file_scope, function_scope, *second) + self.enforce_expression(cs, file_scope, function_scope, expected_types, *second) } else { - self.enforce_expression(cs, file_scope, function_scope, *third) + self.enforce_expression(cs, file_scope, function_scope, expected_types, *third) } } // Arrays Expression::Array(array) => { - self.enforce_array_expression(cs, file_scope, function_scope, array) + self.enforce_array_expression(cs, file_scope, function_scope, expected_types, array) } Expression::ArrayAccess(array, index) => { - self.enforce_array_access_expression(cs, file_scope, function_scope, array, *index) + self.enforce_array_access_expression(cs, file_scope, function_scope, expected_types, array, *index) } // Circuits @@ -833,6 +869,7 @@ impl> ConstrainedProgra cs, file_scope, function_scope, + expected_types, circuit_name, members, ), @@ -841,6 +878,7 @@ impl> ConstrainedProgra cs, file_scope, function_scope, + expected_types, circuit_variable, circuit_member, ), @@ -849,6 +887,7 @@ impl> ConstrainedProgra cs, file_scope, function_scope, + expected_types, circuit_identifier, circuit_member, ), @@ -858,6 +897,7 @@ impl> ConstrainedProgra cs, file_scope, function_scope, + expected_types, function, arguments, ), diff --git a/compiler/src/constraints/function.rs b/compiler/src/constraints/function.rs index c1e0517070..e0e4f7fd1e 100644 --- a/compiler/src/constraints/function.rs +++ b/compiler/src/constraints/function.rs @@ -34,7 +34,7 @@ impl> ConstrainedProgra Expression::Identifier(identifier) => { Ok(self.evaluate_identifier(caller_scope, function_name, identifier)?) } - expression => Ok(self.enforce_expression(cs, scope, function_name, expression)?), + expression => Ok(self.enforce_expression(cs, scope, function_name, vec![], expression)?), } } diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index c491350ab7..4ad6a93beb 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -54,7 +54,7 @@ impl> ConstrainedProgra match range_or_expression { RangeOrExpression::Expression(index) => { let index = - self.enforce_index(cs, file_scope.clone(), function_scope.clone(), index)?; + self.enforce_index(cs, file_scope.clone(), function_scope.clone(), vec![], index)?; // Modify the single value of the array in place match self.get_mutable_assignee(name)? { @@ -137,7 +137,7 @@ impl> ConstrainedProgra // Evaluate new value let new_value = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expression)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), vec![], expression)?; // Mutate the old value into the new value match assignee { @@ -193,8 +193,12 @@ impl> ConstrainedProgra variable: Variable, expression: Expression, ) -> Result<(), StatementError> { + let mut expected_types = vec![]; + if let Some(ref _type) = variable._type { + expected_types.push(_type.clone()); + } let value = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expression)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_types, expression)?; self.store_definition(function_scope, variable, value) } @@ -207,11 +211,19 @@ impl> ConstrainedProgra variables: Vec>, function: Expression, ) -> Result<(), StatementError> { + let mut expected_types = vec![]; + for variable in variables.iter() { + if let Some(ref _type) = variable._type { + expected_types.push(_type.clone()); + } + } + // Expect return values from function let return_values = match self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, function, )? { ConstrainedValue::Return(values) => values, @@ -252,10 +264,12 @@ impl> ConstrainedProgra let mut returns = vec![]; for (expression, ty) in expressions.into_iter().zip(return_types.into_iter()) { + let expected_types = vec![ty.clone()]; let result = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, expression, )?; result.expect_type(&ty)?; @@ -300,10 +314,12 @@ impl> ConstrainedProgra statement: ConditionalStatement, return_types: Vec>, ) -> Result>, StatementError> { + let expected_types = vec![Type::Boolean]; let condition = match self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), + expected_types, statement.condition.clone(), )? { ConstrainedValue::Boolean(resolved) => resolved, @@ -488,14 +504,14 @@ impl> ConstrainedProgra } Statement::AssertEq(left, right) => { let resolved_left = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), left)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), vec![], left)?; let resolved_right = - self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), right)?; + self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), vec![], right)?; self.enforce_assert_eq_statement(cs, resolved_left, resolved_right)?; } Statement::Expression(expression) => { - match self.enforce_expression(cs, file_scope, function_scope, expression.clone())? { + match self.enforce_expression(cs, file_scope, function_scope, vec![], expression.clone())? { ConstrainedValue::Return(values) => { if !values.is_empty() { return Err(StatementError::Unassigned(expression.to_string())); diff --git a/compiler/src/errors/constraints/expression.rs b/compiler/src/errors/constraints/expression.rs index 615febaa85..539ea0289c 100644 --- a/compiler/src/errors/constraints/expression.rs +++ b/compiler/src/errors/constraints/expression.rs @@ -7,6 +7,9 @@ pub enum ExpressionError { UndefinedIdentifier(String), // Types + #[error("Expected single type for implicit number {}", _0)] + SingleType(String), + #[error("{}", _0)] IncompatibleTypes(String),