diff --git a/Cargo.lock b/Cargo.lock index e9958af6f4..85e1eab4e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,18 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "bech32" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" + [[package]] name = "bincode" version = "1.2.1" @@ -327,7 +339,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.33", ] [[package]] @@ -395,7 +407,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.33", "synstructure", ] @@ -837,7 +849,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.18", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.33", ] [[package]] @@ -1062,22 +1074,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.112" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" +checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.112" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" +checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.33", ] [[package]] @@ -1185,13 +1197,15 @@ version = "0.1.0" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.33", ] [[package]] name = "snarkos-errors" version = "0.8.0" dependencies = [ + "base58", + "bech32", "bincode", "curl", "hex", @@ -1235,6 +1249,7 @@ version = "0.8.0" name = "snarkos-utilities" version = "0.8.0" dependencies = [ + "bincode", "rand", "snarkos-derives", "snarkos-errors", @@ -1277,9 +1292,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.31" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" +checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", @@ -1294,7 +1309,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.33", "unicode-xid 0.2.0", ] @@ -1333,7 +1348,7 @@ checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.33", ] [[package]] diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 7bef959cc0..40886ba32a 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -21,7 +21,7 @@ LINE_END = { ";" ~ NEWLINE* } mutable = { "mut" } // Declared in common/range.rs -range = { from_expression? ~ ".." ~ to_expression } +range = { from_expression? ~ ".." ~ to_expression? } from_expression = { expression } to_expression = { expression } diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index ab42c64421..4b5ea8be63 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -29,11 +29,11 @@ pub struct Compiler> { } impl> Compiler { - pub fn new() -> Self { + pub fn new(package_name: String) -> Self { Self { - package_name: "".to_string(), + package_name: package_name.clone(), main_file_path: PathBuf::new(), - program: Program::new(), + program: Program::new(package_name), program_inputs: Inputs::new(), output: None, _engine: PhantomData, @@ -41,14 +41,8 @@ impl> Compiler { } pub fn init(package_name: String, main_file_path: PathBuf) -> Result { - let mut program = Self { - package_name, - main_file_path, - program: Program::new(), - program_inputs: Inputs::new(), - output: None, - _engine: PhantomData, - }; + let mut program = Self::new(package_name); + program.set_path(main_file_path); // Generate the abstract syntax tree and assemble the program let program_string = program.load_program()?; @@ -57,6 +51,10 @@ impl> Compiler { Ok(program) } + pub fn set_path(&mut self, main_file_path: PathBuf) { + self.main_file_path = main_file_path + } + pub fn set_inputs(&mut self, program_inputs: Vec>) { self.program_inputs.set_inputs(program_inputs); } @@ -78,7 +76,12 @@ impl> Compiler { self, cs: &mut CS, ) -> Result, CompilerError> { - generate_constraints(cs, self.program, self.program_inputs.get_inputs()) + let path = self.main_file_path; + generate_constraints(cs, self.program, self.program_inputs.get_inputs()).map_err(|mut error| { + error.set_path(path); + + error + }) } pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem) -> Result<(), CompilerError> { @@ -117,13 +120,14 @@ impl> Compiler { impl> ConstraintSynthesizer for Compiler { fn generate_constraints>(self, cs: &mut CS) -> Result<(), SynthesisError> { - let _result = + let result = generate_constraints::<_, G, _>(cs, self.program, self.program_inputs.get_inputs()).map_err(|e| { log::error!("{}", e); SynthesisError::Unsatisfiable })?; // Write results to file or something + log::info!("{}", result); Ok(()) } diff --git a/compiler/src/constraints/boolean.rs b/compiler/src/constraints/boolean.rs index f041cd1671..764f548628 100644 --- a/compiler/src/constraints/boolean.rs +++ b/compiler/src/constraints/boolean.rs @@ -1,11 +1,7 @@ //! Methods to enforce constraints on booleans in a resolved Leo program. -use crate::{ - constraints::{ConstrainedProgram, ConstrainedValue}, - errors::BooleanError, - GroupType, -}; -use leo_types::InputValue; +use crate::{constraints::ConstrainedValue, errors::BooleanError, GroupType}; +use leo_types::{InputValue, Span}; use snarkos_errors::gadgets::SynthesisError; use snarkos_models::{ @@ -16,68 +12,96 @@ use snarkos_models::{ }, }; -impl> ConstrainedProgram { - pub(crate) fn bool_from_input>( - &mut self, - cs: &mut CS, - name: String, - input_value: Option, - ) -> Result, BooleanError> { - // Check that the input value is the correct type - let bool_value = match input_value { - Some(input) => { - if let InputValue::Boolean(bool) = input { - Some(bool) - } else { - return Err(BooleanError::SynthesisError(SynthesisError::AssignmentMissing)); - } +pub(crate) fn new_bool_constant(string: String, span: Span) -> Result { + let boolean = string + .parse::() + .map_err(|_| BooleanError::invalid_boolean(string, span))?; + + Ok(Boolean::constant(boolean)) +} + +pub(crate) fn allocate_bool>( + cs: &mut CS, + name: String, + option: Option, + span: Span, +) -> Result { + let boolean_name = format!("{}: bool", name); + let boolean_name_unique = format!("`{}` {}:{}", boolean_name, span.line, span.start); + + Boolean::alloc(cs.ns(|| boolean_name_unique), || { + option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| BooleanError::missing_boolean(boolean_name, span)) +} + +pub(crate) fn bool_from_input, CS: ConstraintSystem>( + cs: &mut CS, + name: String, + input_value: Option, + span: Span, +) -> Result, BooleanError> { + // Check that the input value is the correct type + let option = match input_value { + Some(input) => { + if let InputValue::Boolean(bool) = input { + Some(bool) + } else { + return Err(BooleanError::invalid_boolean(name, span)); } - None => None, - }; - - let number = Boolean::alloc(cs.ns(|| name), || bool_value.ok_or(SynthesisError::AssignmentMissing))?; - - Ok(ConstrainedValue::Boolean(number)) - } - - pub(crate) fn evaluate_not(value: ConstrainedValue) -> Result, BooleanError> { - match value { - ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())), - value => Err(BooleanError::CannotEvaluate(format!("!{}", value))), } - } + None => None, + }; - pub(crate) fn enforce_or>( - &mut self, - cs: &mut CS, - left: ConstrainedValue, - right: ConstrainedValue, - ) -> Result, BooleanError> { - match (left, right) { - (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => { - Ok(ConstrainedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool)?)) - } - (left_value, right_value) => Err(BooleanError::CannotEnforce(format!( - "{} || {}", - left_value, right_value - ))), - } - } + let number = allocate_bool(cs, name, option, span)?; - pub(crate) fn enforce_and>( - &mut self, - cs: &mut CS, - left: ConstrainedValue, - right: ConstrainedValue, - ) -> Result, BooleanError> { - match (left, right) { - (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => { - Ok(ConstrainedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool)?)) - } - (left_value, right_value) => Err(BooleanError::CannotEnforce(format!( - "{} && {}", - left_value, right_value - ))), - } + Ok(ConstrainedValue::Boolean(number)) +} + +pub(crate) fn evaluate_not>( + value: ConstrainedValue, + span: Span, +) -> Result, BooleanError> { + match value { + ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())), + value => Err(BooleanError::cannot_evaluate(format!("!{}", value), span)), } } + +pub(crate) fn enforce_or, CS: ConstraintSystem>( + cs: &mut CS, + left: ConstrainedValue, + right: ConstrainedValue, + span: Span, +) -> Result, BooleanError> { + let name = format!("{} || {}", left, right); + + if let (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) = (left, right) { + let name_unique = format!("{} {}:{}", name, span.line, span.start); + let result = Boolean::or(cs.ns(|| name_unique), &left_bool, &right_bool) + .map_err(|e| BooleanError::cannot_enforce(format!("||"), e, span))?; + + return Ok(ConstrainedValue::Boolean(result)); + } + + Err(BooleanError::cannot_evaluate(name, span)) +} + +pub(crate) fn enforce_and, CS: ConstraintSystem>( + cs: &mut CS, + left: ConstrainedValue, + right: ConstrainedValue, + span: Span, +) -> Result, BooleanError> { + let name = format!("{} && {}", left, right); + + if let (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) = (left, right) { + let name_unique = format!("{} {}:{}", name, span.line, span.start); + let result = Boolean::and(cs.ns(|| name_unique), &left_bool, &right_bool) + .map_err(|e| BooleanError::cannot_enforce(format!("&&"), e, span))?; + + return Ok(ConstrainedValue::Boolean(result)); + } + + Err(BooleanError::cannot_evaluate(name, span)) +} diff --git a/compiler/src/constraints/expression.rs b/compiler/src/constraints/expression.rs index eb9777dc7d..8a1ee60d0b 100644 --- a/compiler/src/constraints/expression.rs +++ b/compiler/src/constraints/expression.rs @@ -2,7 +2,10 @@ use crate::{ constraints::{ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue}, + enforce_and, + enforce_or, errors::ExpressionError, + evaluate_not, new_scope, FieldType, GroupType, @@ -51,7 +54,7 @@ impl> ConstrainedProgram { return Err(ExpressionError::undefined_identifier(unresolved_identifier)); }; - result_value.resolve_type(expected_types)?; + result_value.resolve_type(expected_types, unresolved_identifier.span.clone())?; Ok(result_value) } @@ -66,20 +69,20 @@ impl> ConstrainedProgram { ) -> Result, ExpressionError> { match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - Ok(ConstrainedValue::Integer(num_1.add(cs, num_2)?)) + Ok(ConstrainedValue::Integer(num_1.add(cs, num_2, span)?)) } (ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { - Ok(ConstrainedValue::Field(fe_1.add(cs, &fe_2)?)) + Ok(ConstrainedValue::Field(fe_1.add(cs, &fe_2, span)?)) } (ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => { - Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2)?)) + Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2, span)?)) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.enforce_add_expression(cs, val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.enforce_add_expression(cs, val_1, val_2, span) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -98,20 +101,20 @@ impl> ConstrainedProgram { ) -> Result, ExpressionError> { match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - Ok(ConstrainedValue::Integer(num_1.sub(cs, num_2)?)) + Ok(ConstrainedValue::Integer(num_1.sub(cs, num_2, span)?)) } (ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { - Ok(ConstrainedValue::Field(fe_1.sub(cs, &fe_2)?)) + Ok(ConstrainedValue::Field(fe_1.sub(cs, &fe_2, span)?)) } (ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => { - Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2)?)) + Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2, span)?)) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.enforce_sub_expression(cs, val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.enforce_sub_expression(cs, val_1, val_2, span) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -130,17 +133,17 @@ impl> ConstrainedProgram { ) -> Result, ExpressionError> { match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - Ok(ConstrainedValue::Integer(num_1.mul(cs, num_2)?)) + Ok(ConstrainedValue::Integer(num_1.mul(cs, num_2, span)?)) } (ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { - Ok(ConstrainedValue::Field(fe_1.mul(cs, &fe_2)?)) + Ok(ConstrainedValue::Field(fe_1.mul(cs, &fe_2, span)?)) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.enforce_mul_expression(cs, val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.enforce_mul_expression(cs, val_1, val_2, span) } (val_1, val_2) => { @@ -161,17 +164,17 @@ impl> ConstrainedProgram { ) -> Result, ExpressionError> { match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - Ok(ConstrainedValue::Integer(num_1.div(cs, num_2)?)) + Ok(ConstrainedValue::Integer(num_1.div(cs, num_2, span)?)) } (ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { - Ok(ConstrainedValue::Field(fe_1.div(cs, &fe_2)?)) + Ok(ConstrainedValue::Field(fe_1.div(cs, &fe_2, span)?)) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.enforce_div_expression(cs, val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.enforce_div_expression(cs, val_1, val_2, span) } (val_1, val_2) => { @@ -192,14 +195,14 @@ impl> ConstrainedProgram { ) -> Result, ExpressionError> { match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - Ok(ConstrainedValue::Integer(num_1.pow(cs, num_2)?)) + Ok(ConstrainedValue::Integer(num_1.pow(cs, num_2, span)?)) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.enforce_pow_expression(cs, val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.enforce_pow_expression(cs, val_1, val_2, span) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -217,27 +220,27 @@ impl> ConstrainedProgram { right: ConstrainedValue, span: Span, ) -> Result, ExpressionError> { - let mut expression_namespace = cs.ns(|| format!("evaluate {} == {}", left.to_string(), right.to_string())); - let result_bool = match (left, right) { + let mut unique_namespace = cs.ns(|| format!("evaluate {} == {} {}:{}", left, right, span.line, span.start)); + let constraint_result = match (left, right) { (ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => { - bool_1.evaluate_equal(expression_namespace, &bool_2)? + bool_1.evaluate_equal(unique_namespace, &bool_2) } (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - num_1.evaluate_equal(expression_namespace, &num_2)? + num_1.evaluate_equal(unique_namespace, &num_2) } (ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { - fe_1.evaluate_equal(expression_namespace, &fe_2)? + fe_1.evaluate_equal(unique_namespace, &fe_2) } (ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => { - ge_1.evaluate_equal(expression_namespace, &ge_2)? + ge_1.evaluate_equal(unique_namespace, &ge_2) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; - return self.evaluate_eq_expression(&mut expression_namespace, val_1, val_2, span); + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; + return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span); } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; - return self.evaluate_eq_expression(&mut expression_namespace, val_1, val_2, span); + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; + return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span); } (val_1, val_2) => { return Err(ExpressionError::incompatible_types( @@ -247,7 +250,10 @@ impl> ConstrainedProgram { } }; - Ok(ConstrainedValue::Boolean(result_bool)) + let boolean = + constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate equals"), e, span))?; + + Ok(ConstrainedValue::Boolean(boolean)) } //TODO: unsafe for allocated values @@ -267,11 +273,11 @@ impl> ConstrainedProgram { Ok(ConstrainedValue::Boolean(Boolean::Constant(result))) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.evaluate_ge_expression(val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.evaluate_ge_expression(val_1, val_2, span) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -298,11 +304,11 @@ impl> ConstrainedProgram { Ok(ConstrainedValue::Boolean(Boolean::Constant(result))) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.evaluate_gt_expression(val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.evaluate_gt_expression(val_1, val_2, span) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -329,11 +335,11 @@ impl> ConstrainedProgram { Ok(ConstrainedValue::Boolean(Boolean::Constant(result))) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.evaluate_le_expression(val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.evaluate_le_expression(val_1, val_2, span) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -360,11 +366,11 @@ impl> ConstrainedProgram { Ok(ConstrainedValue::Boolean(Boolean::Constant(result))) } (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2)?; + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; self.evaluate_lt_expression(val_1, val_2, span) } (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1)?; + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; self.evaluate_lt_expression(val_1, val_2, span) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -397,25 +403,47 @@ impl> ConstrainedProgram { value => return Err(ExpressionError::conditional_boolean(value.to_string(), span)), }; - let resolved_second = - self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, second)?; - let resolved_third = self.enforce_expression_value(cs, file_scope, function_scope, expected_types, third)?; + let resolved_second = self.enforce_expression_value( + cs, + file_scope.clone(), + function_scope.clone(), + expected_types, + second, + span.clone(), + )?; + let resolved_third = + self.enforce_expression_value(cs, file_scope, function_scope, expected_types, third, span.clone())?; + + let unique_namespace = cs.ns(|| { + format!( + "select {} or {} {}:{}", + resolved_second, resolved_third, span.line, span.start + ) + }); match (resolved_second, resolved_third) { (ConstrainedValue::Boolean(bool_2), ConstrainedValue::Boolean(bool_3)) => { - let result = Boolean::conditionally_select(cs, &resolved_first, &bool_2, &bool_3)?; + let result = Boolean::conditionally_select(unique_namespace, &resolved_first, &bool_2, &bool_3) + .map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?; + Ok(ConstrainedValue::Boolean(result)) } (ConstrainedValue::Integer(integer_2), ConstrainedValue::Integer(integer_3)) => { - let result = Integer::conditionally_select(cs, &resolved_first, &integer_2, &integer_3)?; + let result = Integer::conditionally_select(unique_namespace, &resolved_first, &integer_2, &integer_3) + .map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?; + Ok(ConstrainedValue::Integer(result)) } - (ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { - let result = FieldType::conditionally_select(cs, &resolved_first, &fe_1, &fe_2)?; + (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { + let result = FieldType::conditionally_select(unique_namespace, &resolved_first, &field_1, &field_2) + .map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?; + Ok(ConstrainedValue::Field(result)) } - (ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => { - let result = G::conditionally_select(cs, &resolved_first, &ge_1, &ge_2)?; + (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => { + let result = G::conditionally_select(unique_namespace, &resolved_first, &point_1, &point_2) + .map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?; + Ok(ConstrainedValue::Group(result)) } (val_1, val_2) => Err(ExpressionError::incompatible_types( @@ -507,8 +535,15 @@ impl> ConstrainedProgram { span: Span, ) -> Result { let expected_types = vec![Type::IntegerType(IntegerType::U32)]; - match self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), &expected_types, index)? { - ConstrainedValue::Integer(number) => Ok(number.to_usize()), + match self.enforce_expression_value( + cs, + file_scope.clone(), + function_scope.clone(), + &expected_types, + index, + span.clone(), + )? { + ConstrainedValue::Integer(number) => Ok(number.to_usize(span.clone())?), value => Err(ExpressionError::invalid_index(value.to_string(), span)), } } @@ -529,6 +564,7 @@ impl> ConstrainedProgram { function_scope.clone(), expected_types, *array, + span.clone(), )? { ConstrainedValue::Array(array) => array, value => return Err(ExpressionError::undefined_array(value.to_string(), span)), @@ -537,11 +573,11 @@ impl> ConstrainedProgram { match index { RangeOrExpression::Range(from, to) => { let from_resolved = match from { - Some(from_index) => from_index.to_usize(), + Some(from_index) => from_index.to_usize(span.clone())?, None => 0usize, // Array slice starts at index 0 }; let to_resolved = match to { - Some(to_index) => to_index.to_usize(), + Some(to_index) => to_index.to_usize(span.clone())?, None => array.len(), // Array slice ends at array length }; Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned())) @@ -633,6 +669,7 @@ impl> ConstrainedProgram { function_scope.clone(), expected_types, *circuit_identifier.clone(), + span.clone(), )? { ConstrainedValue::CircuitExpression(name, members) => (name, members), value => return Err(ExpressionError::undefined_circuit(value.to_string(), span)), @@ -757,7 +794,20 @@ impl> ConstrainedProgram { value => return Err(ExpressionError::undefined_function(value.to_string(), span)), }; - match self.enforce_function(cs, outer_scope, function_scope, function_call, arguments) { + let name_unique = format!( + "function call {} {}:{}", + function_call.get_name(), + span.line, + span.start, + ); + + match self.enforce_function( + &mut cs.ns(|| name_unique), + outer_scope, + function_scope, + function_call, + arguments, + ) { Ok(ConstrainedValue::Return(return_values)) => { if return_values.len() == 1 { Ok(return_values[0].clone()) @@ -773,9 +823,10 @@ impl> ConstrainedProgram { pub(crate) fn enforce_number_implicit( expected_types: &Vec, value: String, + span: Span, ) -> Result, ExpressionError> { if expected_types.len() == 1 { - return Ok(ConstrainedValue::from_type(value, &expected_types[0])?); + return Ok(ConstrainedValue::from_type(value, &expected_types[0], span)?); } Ok(ConstrainedValue::Unresolved(value)) @@ -791,11 +842,12 @@ impl> ConstrainedProgram { function_scope: String, expected_types: &Vec, expression: Expression, + span: Span, ) -> Result, ExpressionError> { let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_types, expression)?; branch.get_inner_mut(); - branch.resolve_type(expected_types)?; + branch.resolve_type(expected_types, span)?; Ok(branch) } @@ -808,13 +860,26 @@ impl> ConstrainedProgram { expected_types: &Vec, left: Expression, right: Expression, + span: Span, ) -> Result<(ConstrainedValue, ConstrainedValue), ExpressionError> { - let mut resolved_left = - self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, left)?; - let mut resolved_right = - self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, right)?; + let mut resolved_left = self.enforce_expression_value( + cs, + file_scope.clone(), + function_scope.clone(), + expected_types, + left, + span.clone(), + )?; + let mut resolved_right = self.enforce_expression_value( + cs, + file_scope.clone(), + function_scope.clone(), + expected_types, + right, + span.clone(), + )?; - resolved_left.resolve_types(&mut resolved_right, expected_types)?; + resolved_left.resolve_types(&mut resolved_right, expected_types, span)?; Ok((resolved_left, resolved_right)) } @@ -835,10 +900,10 @@ impl> ConstrainedProgram { // Values Expression::Integer(integer) => Ok(ConstrainedValue::Integer(integer)), - Expression::Field(field) => Ok(ConstrainedValue::Field(FieldType::constant(field)?)), - Expression::Group(group_affine) => Ok(ConstrainedValue::Group(G::constant(group_affine)?)), + Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, span)?)), + Expression::Group(group_affine, span) => Ok(ConstrainedValue::Group(G::constant(group_affine, span)?)), Expression::Boolean(bool) => Ok(ConstrainedValue::Boolean(bool)), - Expression::Implicit(value) => Self::enforce_number_implicit(expected_types, value), + Expression::Implicit(value, span) => Self::enforce_number_implicit(expected_types, value, span), // Binary operations Expression::Add(left, right, span) => { @@ -849,6 +914,7 @@ impl> ConstrainedProgram { expected_types, *left, *right, + span.clone(), )?; self.enforce_add_expression(cs, resolved_left, resolved_right, span) @@ -861,6 +927,7 @@ impl> ConstrainedProgram { expected_types, *left, *right, + span.clone(), )?; self.enforce_sub_expression(cs, resolved_left, resolved_right, span) @@ -873,6 +940,7 @@ impl> ConstrainedProgram { expected_types, *left, *right, + span.clone(), )?; self.enforce_mul_expression(cs, resolved_left, resolved_right, span) @@ -885,6 +953,7 @@ impl> ConstrainedProgram { expected_types, *left, *right, + span.clone(), )?; self.enforce_div_expression(cs, resolved_left, resolved_right, span) @@ -897,20 +966,18 @@ impl> ConstrainedProgram { expected_types, *left, *right, + span.clone(), )?; self.enforce_pow_expression(cs, resolved_left, resolved_right, span) } // Boolean operations - Expression::Not(expression) => Ok(Self::evaluate_not(self.enforce_expression( - cs, - file_scope, - function_scope, - expected_types, - *expression, - )?)?), - Expression::Or(left, right, _span) => { + Expression::Not(expression, span) => Ok(evaluate_not( + self.enforce_expression(cs, file_scope, function_scope, expected_types, *expression)?, + span, + )?), + Expression::Or(left, right, span) => { let (resolved_left, resolved_right) = self.enforce_binary_expression( cs, file_scope.clone(), @@ -918,11 +985,12 @@ impl> ConstrainedProgram { expected_types, *left, *right, + span.clone(), )?; - Ok(self.enforce_or(cs, resolved_left, resolved_right)?) + Ok(enforce_or(cs, resolved_left, resolved_right, span)?) } - Expression::And(left, right, _span) => { + Expression::And(left, right, span) => { let (resolved_left, resolved_right) = self.enforce_binary_expression( cs, file_scope.clone(), @@ -930,9 +998,10 @@ impl> ConstrainedProgram { expected_types, *left, *right, + span.clone(), )?; - Ok(self.enforce_and(cs, resolved_left, resolved_right)?) + Ok(enforce_and(cs, resolved_left, resolved_right, span)?) } Expression::Eq(left, right, span) => { let (resolved_left, resolved_right) = self.enforce_binary_expression( @@ -942,6 +1011,7 @@ impl> ConstrainedProgram { &vec![], *left, *right, + span.clone(), )?; Ok(self.evaluate_eq_expression(cs, resolved_left, resolved_right, span)?) @@ -954,6 +1024,7 @@ impl> ConstrainedProgram { &vec![], *left, *right, + span.clone(), )?; Ok(self.evaluate_ge_expression(resolved_left, resolved_right, span)?) @@ -966,6 +1037,7 @@ impl> ConstrainedProgram { &vec![], *left, *right, + span.clone(), )?; Ok(self.evaluate_gt_expression(resolved_left, resolved_right, span)?) @@ -978,6 +1050,7 @@ impl> ConstrainedProgram { &vec![], *left, *right, + span.clone(), )?; Ok(self.evaluate_le_expression(resolved_left, resolved_right, span)?) @@ -990,6 +1063,7 @@ impl> ConstrainedProgram { &vec![], *left, *right, + span.clone(), )?; Ok(self.evaluate_lt_expression(resolved_left, resolved_right, span)?) diff --git a/compiler/src/constraints/field.rs b/compiler/src/constraints/field.rs index c1990c6c38..fe036a1e95 100644 --- a/compiler/src/constraints/field.rs +++ b/compiler/src/constraints/field.rs @@ -1,7 +1,7 @@ //! Methods to enforce constraints on field elements in a resolved Leo program. use crate::{constraints::ConstrainedValue, errors::FieldError, FieldType, GroupType}; -use leo_types::InputValue; +use leo_types::{InputValue, Span}; use snarkos_errors::gadgets::SynthesisError; use snarkos_models::{ @@ -9,24 +9,40 @@ use snarkos_models::{ gadgets::{r1cs::ConstraintSystem, utilities::alloc::AllocGadget}, }; +pub(crate) fn allocate_field>( + cs: &mut CS, + name: String, + option: Option, + span: Span, +) -> Result, FieldError> { + let field_name = format!("{}: field", name); + let field_name_unique = format!("`{}` {}:{}", field_name, span.line, span.start); + + FieldType::alloc(cs.ns(|| field_name_unique), || { + option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| FieldError::missing_field(field_name, span)) +} + pub(crate) fn field_from_input, CS: ConstraintSystem>( cs: &mut CS, name: String, input_value: Option, + span: Span, ) -> Result, FieldError> { // Check that the parameter value is the correct type - let field_option = match input_value { + let option = match input_value { Some(input) => { if let InputValue::Field(string) = input { Some(string) } else { - return Err(FieldError::Invalid(input.to_string())); + return Err(FieldError::invalid_field(input.to_string(), span)); } } None => None, }; - let field_value = FieldType::alloc(cs.ns(|| name), || field_option.ok_or(SynthesisError::AssignmentMissing))?; + let field = allocate_field(cs, name, option, span)?; - Ok(ConstrainedValue::Field(field_value)) + Ok(ConstrainedValue::Field(field)) } diff --git a/compiler/src/constraints/function.rs b/compiler/src/constraints/function.rs index bfc8c435ac..3603d7a4a3 100644 --- a/compiler/src/constraints/function.rs +++ b/compiler/src/constraints/function.rs @@ -2,6 +2,7 @@ //! a resolved Leo program. use crate::{ + bool_from_input, constraints::{new_scope, ConstrainedProgram, ConstrainedValue}, errors::{FunctionError, ImportError}, field_from_input, @@ -169,10 +170,11 @@ impl> ConstrainedProgram { integer_type, name, input_value, + span, )?)), - Type::Field => Ok(field_from_input(cs, name, input_value)?), - Type::Group => Ok(group_from_input(cs, name, input_value)?), - Type::Boolean => Ok(self.bool_from_input(cs, name, input_value)?), + Type::Field => Ok(field_from_input(cs, name, input_value, span)?), + Type::Group => Ok(group_from_input(cs, name, input_value, span)?), + Type::Boolean => Ok(bool_from_input(cs, name, input_value, span)?), Type::Array(_type, dimensions) => self.allocate_array(cs, name, *_type, dimensions, input_value, span), _ => unimplemented!("main function input not implemented for type"), } @@ -193,16 +195,16 @@ impl> ConstrainedProgram { // Iterate over main function inputs and allocate new passed-by variable values let mut input_variables = vec![]; for (input_model, input_option) in function.inputs.clone().into_iter().zip(inputs.into_iter()) { - let input_name = new_scope(function_name.clone(), input_model.identifier.name.clone()); let input_value = self.allocate_main_function_input( cs, input_model._type, - input_name.clone(), + input_model.identifier.name.clone(), input_option, function.span.clone(), )?; // Store a new variable for every allocated main function input + let input_name = new_scope(function_name.clone(), input_model.identifier.name.clone()); self.store(input_name.clone(), input_value); input_variables.push(Expression::Identifier(input_model.identifier)); @@ -211,18 +213,14 @@ impl> ConstrainedProgram { self.enforce_function(cs, scope, function_name, function, input_variables) } - pub(crate) fn resolve_definitions>( - &mut self, - cs: &mut CS, - program: Program, - ) -> Result<(), ImportError> { + pub(crate) fn resolve_definitions(&mut self, program: Program) -> Result<(), ImportError> { let program_name = program.name.clone(); // evaluate and store all imports program .imports .into_iter() - .map(|import| self.enforce_import(cs, program_name.clone(), import)) + .map(|import| self.enforce_import(program_name.clone(), import)) .collect::, ImportError>>()?; // evaluate and store all circuit definitions diff --git a/compiler/src/constraints/group.rs b/compiler/src/constraints/group.rs index 93c90d0f71..fd717392e8 100644 --- a/compiler/src/constraints/group.rs +++ b/compiler/src/constraints/group.rs @@ -1,5 +1,5 @@ use crate::{errors::GroupError, ConstrainedValue, GroupType}; -use leo_types::InputValue; +use leo_types::{InputValue, Span}; use snarkos_errors::gadgets::SynthesisError; use snarkos_models::{ @@ -7,24 +7,40 @@ use snarkos_models::{ gadgets::r1cs::ConstraintSystem, }; +pub(crate) fn allocate_group, CS: ConstraintSystem>( + cs: &mut CS, + name: String, + option: Option, + span: Span, +) -> Result { + let group_name = format!("{}: group", name); + let group_name_unique = format!("`{}` {}:{}", group_name, span.line, span.start); + + G::alloc(cs.ns(|| group_name_unique), || { + option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| GroupError::missing_group(group_name, span)) +} + pub(crate) fn group_from_input, CS: ConstraintSystem>( cs: &mut CS, name: String, input_value: Option, + span: Span, ) -> Result, GroupError> { // Check that the parameter value is the correct type - let group_option = match input_value { + let option = match input_value { Some(input) => { if let InputValue::Group(string) = input { Some(string) } else { - return Err(GroupError::Invalid(input.to_string())); + return Err(GroupError::invalid_group(input.to_string(), span)); } } None => None, }; - let group_value = G::alloc(cs.ns(|| name), || group_option.ok_or(SynthesisError::AssignmentMissing))?; + let group = allocate_group(cs, name, option, span)?; - Ok(ConstrainedValue::Group(group_value)) + Ok(ConstrainedValue::Group(group)) } diff --git a/compiler/src/constraints/import.rs b/compiler/src/constraints/import.rs index d9c20b34b6..0c351a64d5 100644 --- a/compiler/src/constraints/import.rs +++ b/compiler/src/constraints/import.rs @@ -7,20 +7,12 @@ use crate::{ use leo_ast::LeoParser; use leo_types::{Import, Program}; -use snarkos_models::{ - curves::{Field, PrimeField}, - gadgets::r1cs::ConstraintSystem, -}; +use snarkos_models::curves::{Field, PrimeField}; use std::env::current_dir; impl> ConstrainedProgram { - pub fn enforce_import>( - &mut self, - cs: &mut CS, - scope: String, - import: Import, - ) -> Result<(), ImportError> { - let path = current_dir().map_err(|error| ImportError::DirectoryError(error))?; + pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> { + let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; // Sanitize the package path to the imports directory let mut package_path = path.clone(); @@ -48,9 +40,7 @@ impl> ConstrainedProgram { // * -> import all imports, circuits, functions in the current scope if import.is_star() { // recursively evaluate program statements - self.resolve_definitions(cs, program).unwrap(); - - Ok(()) + self.resolve_definitions(program) } else { let program_name = program.name.clone(); @@ -75,11 +65,7 @@ impl> ConstrainedProgram { match matched_function { Some((_function_name, function)) => ConstrainedValue::Function(None, function), - None => unimplemented!( - "cannot find imported symbol {} in imported file {}", - symbol, - program_name.clone() - ), + None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)), } } }; @@ -96,7 +82,7 @@ impl> ConstrainedProgram { program .imports .into_iter() - .map(|nested_import| self.enforce_import(cs, program_name.clone(), nested_import)) + .map(|nested_import| self.enforce_import(program_name.clone(), nested_import)) .collect::, ImportError>>()?; Ok(()) diff --git a/compiler/src/constraints/mod.rs b/compiler/src/constraints/mod.rs index c4c5c6494f..2045087aff 100644 --- a/compiler/src/constraints/mod.rs +++ b/compiler/src/constraints/mod.rs @@ -1,7 +1,7 @@ //! Module containing methods to enforce constraints in an Leo program -pub mod boolean; -pub use boolean::*; +pub(crate) mod boolean; +pub(crate) use boolean::*; pub mod function; pub use function::*; @@ -44,7 +44,7 @@ pub fn generate_constraints, CS: Constrai let program_name = program.get_name(); let main_function_name = new_scope(program_name.clone(), "main".into()); - resolved_program.resolve_definitions(cs, program)?; + resolved_program.resolve_definitions(program)?; let main = resolved_program .get(&main_function_name) @@ -69,7 +69,7 @@ pub fn generate_test_constraints>( let tests = program.tests.clone(); - resolved_program.resolve_definitions(cs, program)?; + resolved_program.resolve_definitions(program)?; log::info!("Running {} tests", tests.len()); diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index 36aaef1a97..27e442dcb5 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -21,6 +21,7 @@ use leo_types::{ Variable, }; +use crate::errors::ValueError; use snarkos_models::{ curves::{Field, PrimeField}, gadgets::{ @@ -74,12 +75,18 @@ impl> ConstrainedProgram { // Modify the single value of the array in place match self.get_mutable_assignee(name, span.clone())? { ConstrainedValue::Array(old) => { - new_value.resolve_type(&vec![old[index].to_type()])?; + new_value.resolve_type(&vec![old[index].to_type(span.clone())?], span.clone())?; - let selected_value = - ConstrainedValue::conditionally_select(cs, &condition, &new_value, &old[index]).map_err( - |_| StatementError::select_fail(new_value.to_string(), old[index].to_string(), span), - )?; + let name_unique = format!("select {} {}:{}", new_value, span.line, span.start); + let selected_value = ConstrainedValue::conditionally_select( + cs.ns(|| name_unique), + &condition, + &new_value, + &old[index], + ) + .map_err(|_| { + StatementError::select_fail(new_value.to_string(), old[index].to_string(), span) + })?; old[index] = selected_value; } @@ -88,11 +95,11 @@ impl> ConstrainedProgram { } RangeOrExpression::Range(from, to) => { let from_index = match from { - Some(integer) => integer.to_usize(), + Some(integer) => integer.to_usize(span.clone())?, None => 0usize, }; let to_index_option = match to { - Some(integer) => Some(integer.to_usize()), + Some(integer) => Some(integer.to_usize(span.clone())?), None => None, }; @@ -107,8 +114,11 @@ impl> ConstrainedProgram { } _ => return Err(StatementError::array_assign_range(span)), }; - let selected_array = ConstrainedValue::conditionally_select(cs, &condition, &new_array, old_array) - .map_err(|_| StatementError::select_fail(new_array.to_string(), old_array.to_string(), span))?; + let name_unique = format!("select {} {}:{}", new_array, span.line, span.start); + let selected_array = + ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_array, old_array) + .map_err(|_| StatementError::select_fail(new_array.to_string(), old_array.to_string(), span))?; + *old_array = selected_array; } } @@ -144,12 +154,18 @@ impl> ConstrainedProgram { return Err(StatementError::immutable_circuit_function("static".into(), span)); } _ => { - new_value.resolve_type(&vec![object.1.to_type()])?; + new_value.resolve_type(&vec![object.1.to_type(span.clone())?], span.clone())?; - let selected_value = - ConstrainedValue::conditionally_select(cs, &condition, &new_value, &object.1).map_err( - |_| StatementError::select_fail(new_value.to_string(), object.1.to_string(), span), - )?; + let name_unique = format!("select {} {}:{}", new_value, span.line, span.start); + let selected_value = ConstrainedValue::conditionally_select( + cs.ns(|| name_unique), + &condition, + &new_value, + &object.1, + ) + .map_err(|_| { + StatementError::select_fail(new_value.to_string(), object.1.to_string(), span) + })?; object.1 = selected_value.to_owned(); } @@ -185,9 +201,13 @@ impl> ConstrainedProgram { Assignee::Identifier(_identifier) => { let condition = indicator.unwrap_or(Boolean::Constant(true)); let old_value = self.get_mutable_assignee(variable_name.clone(), span.clone())?; - new_value.resolve_type(&vec![old_value.to_type()])?; - let selected_value = ConstrainedValue::conditionally_select(cs, &condition, &new_value, old_value) - .map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span))?; + + new_value.resolve_type(&vec![old_value.to_type(span.clone())?], span.clone())?; + + let name_unique = format!("select {} {}:{}", new_value, span.line, span.start); + let selected_value = + ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_value, old_value) + .map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span))?; *old_value = selected_value; @@ -235,7 +255,7 @@ impl> ConstrainedProgram { declare: Declare, variable: Variable, expression: Expression, - _span: Span, + span: Span, ) -> Result<(), StatementError> { let mut expected_types = vec![]; if let Some(ref _type) = variable._type { @@ -250,7 +270,7 @@ impl> ConstrainedProgram { )?; if let Declare::Let = declare { - value.allocate_value(cs)?; + value.allocate_value(cs, span)?; } self.store_definition(function_scope, variable, value) @@ -298,6 +318,27 @@ impl> ConstrainedProgram { Ok(()) } + fn check_return_types(expected: &Vec, actual: &Vec, span: Span) -> Result<(), StatementError> { + expected + .iter() + .zip(actual.iter()) + .map(|(type_1, type_2)| { + if type_1.ne(type_2) { + // catch return Self type + if type_1.is_self() && type_2.is_circuit() { + Ok(()) + } else { + Err(StatementError::arguments_type(type_1, type_2, span.clone())) + } + } else { + Ok(()) + } + }) + .collect::, StatementError>>()?; + + Ok(()) + } + fn enforce_return_statement>( &mut self, cs: &mut CS, @@ -317,7 +358,7 @@ impl> ConstrainedProgram { } let mut returns = vec![]; - for (expression, ty) in expressions.into_iter().zip(return_types.into_iter()) { + for (expression, ty) in expressions.into_iter().zip(return_types.clone().into_iter()) { let expected_types = vec![ty.clone()]; let result = self.enforce_expression_value( cs, @@ -325,11 +366,19 @@ impl> ConstrainedProgram { function_scope.clone(), &expected_types, expression, + span.clone(), )?; returns.push(result); } + let actual_types = returns + .iter() + .map(|value| value.to_type(span.clone())) + .collect::, ValueError>>()?; + + Self::check_return_types(&return_types, &actual_types, span)?; + Ok(ConstrainedValue::Return(returns)) } @@ -390,12 +439,25 @@ impl> ConstrainedProgram { value => return Err(StatementError::conditional_boolean(value.to_string(), span)), }; - // Determine nested branch selection + // Determine nested branch 1 selection + let outer_indicator_string = outer_indicator + .get_value() + .map(|b| b.to_string()) + .unwrap_or(format!("[allocated]")); + let inner_indicator_string = inner_indicator + .get_value() + .map(|b| b.to_string()) + .unwrap_or(format!("[allocated]")); + let branch_1_name = format!( + "branch indicator 1 {} && {}", + outer_indicator_string, inner_indicator_string + ); let branch_1_indicator = Boolean::and( - &mut cs.ns(|| format!("statement branch 1 indicator {}", statement_string)), + &mut cs.ns(|| format!("branch 1 {} {}:{}", statement_string, span.line, span.start)), &outer_indicator, &inner_indicator, - )?; + ) + .map_err(|_| StatementError::indicator_calculation(branch_1_name, span.clone()))?; // Execute branch 1 self.evaluate_branch( @@ -407,13 +469,24 @@ impl> ConstrainedProgram { return_types.clone(), )?; - // Execute branch 2 + // Determine nested branch 2 selection + let inner_indicator = inner_indicator.not(); + let inner_indicator_string = inner_indicator + .get_value() + .map(|b| b.to_string()) + .unwrap_or(format!("[allocated]")); + let branch_2_name = format!( + "branch indicator 2 {} && {}", + outer_indicator_string, inner_indicator_string + ); let branch_2_indicator = Boolean::and( - &mut cs.ns(|| format!("statement branch 2 indicator {}", statement_string)), + &mut cs.ns(|| format!("branch 2 {} {}:{}", statement_string, span.line, span.start)), &outer_indicator, - &inner_indicator.not(), - )?; + &inner_indicator, + ) + .map_err(|_| StatementError::indicator_calculation(branch_2_name, span.clone()))?; + // Execute branch 2 match statement.next { Some(next) => match next { ConditionalNestedOrEndStatement::Nested(nested) => self.enforce_conditional_statement( @@ -434,7 +507,7 @@ impl> ConstrainedProgram { return_types, ), }, - None => Ok(None), // this is an if with no else, have to pass statements.conditional down to next statements somehow + None => Ok(None), } } @@ -449,24 +522,26 @@ impl> ConstrainedProgram { stop: Integer, statements: Vec, return_types: Vec, - _span: Span, + span: Span, ) -> Result>, StatementError> { let mut res = None; + let from = start.to_usize(span.clone())?; + let to = stop.to_usize(span.clone())?; - for i in start.to_usize()..stop.to_usize() { + for i in from..to { // Store index in current function scope. // For loop scope is not implemented. let index_name = new_scope(function_scope.clone(), index.to_string()); + self.store( index_name, ConstrainedValue::Integer(Integer::U32(UInt32::constant(i as u32))), ); - cs.ns(|| format!("loop {} = {}", index.to_string(), i)); - // Evaluate statements and possibly return early + let name_unique = format!("for loop iteration {} {}:{}", i, span.line, span.start); if let Some(early_return) = self.evaluate_branch( - cs, + &mut cs.ns(|| name_unique), file_scope.clone(), function_scope.clone(), indicator, @@ -490,7 +565,8 @@ impl> ConstrainedProgram { span: Span, ) -> Result<(), StatementError> { let condition = indicator.unwrap_or(Boolean::Constant(true)); - let result = left.conditional_enforce_equal(cs, right, &condition); + let name_unique = format!("assert {} == {} {}:{}", left, right, span.line, span.start); + let result = left.conditional_enforce_equal(cs.ns(|| name_unique), right, &condition); Ok(result.map_err(|_| StatementError::assertion_failed(left.to_string(), right.to_string(), span))?) } @@ -556,7 +632,7 @@ impl> ConstrainedProgram { } Statement::AssertEq(left, right, span) => { let (resolved_left, resolved_right) = - self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right)?; + self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right, span.clone())?; self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right, span)?; } diff --git a/compiler/src/constraints/value.rs b/compiler/src/constraints/value.rs index 77a9cf31a4..824cea54d5 100644 --- a/compiler/src/constraints/value.rs +++ b/compiler/src/constraints/value.rs @@ -1,20 +1,22 @@ //! The in memory stored value for a defined name in a resolved Leo program. -use crate::{errors::ValueError, FieldType, GroupType}; -use leo_types::{Circuit, Function, Identifier, Integer, IntegerType, Type}; +use crate::{ + allocate_bool, + allocate_field, + allocate_group, + errors::ValueError, + new_bool_constant, + FieldType, + GroupType, +}; +use leo_types::{Circuit, Function, Identifier, Integer, Span, Type}; use snarkos_errors::gadgets::SynthesisError; use snarkos_models::{ curves::{Field, PrimeField}, gadgets::{ r1cs::ConstraintSystem, - utilities::{ - alloc::AllocGadget, - boolean::Boolean, - eq::ConditionalEqGadget, - select::CondSelectGadget, - uint::{UInt128, UInt16, UInt32, UInt64, UInt8}, - }, + utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget}, }, }; use std::fmt; @@ -43,43 +45,55 @@ pub enum ConstrainedValue> { } impl> ConstrainedValue { - pub(crate) fn from_other(value: String, other: &ConstrainedValue) -> Result { - let other_type = other.to_type(); + pub(crate) fn from_other(value: String, other: &ConstrainedValue, span: Span) -> Result { + let other_type = other.to_type(span.clone())?; - ConstrainedValue::from_type(value, &other_type) + ConstrainedValue::from_type(value, &other_type, span) } - pub(crate) fn from_type(value: String, _type: &Type) -> Result { + pub(crate) fn from_type(value: String, _type: &Type, span: Span) -> Result { match _type { - Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(match integer_type { - IntegerType::U8 => Integer::U8(UInt8::constant(value.parse::()?)), - IntegerType::U16 => Integer::U16(UInt16::constant(value.parse::()?)), - IntegerType::U32 => Integer::U32(UInt32::constant(value.parse::()?)), - IntegerType::U64 => Integer::U64(UInt64::constant(value.parse::()?)), - IntegerType::U128 => Integer::U128(UInt128::constant(value.parse::()?)), - })), - Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value)?)), - Type::Group => Ok(ConstrainedValue::Group(G::constant(value)?)), - Type::Boolean => Ok(ConstrainedValue::Boolean(Boolean::Constant(value.parse::()?))), - Type::Array(ref _type, _dimensions) => ConstrainedValue::from_type(value, _type), + Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::new_constant( + integer_type, + value, + span, + )?)), + Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)), + Type::Group => Ok(ConstrainedValue::Group(G::constant(value, span)?)), + Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)), + Type::Array(ref _type, _dimensions) => ConstrainedValue::from_type(value, _type, span), _ => Ok(ConstrainedValue::Unresolved(value)), } } - pub(crate) fn to_type(&self) -> Type { - match self { + pub(crate) fn to_type(&self, span: Span) -> Result { + Ok(match self { ConstrainedValue::Integer(integer) => Type::IntegerType(integer.get_type()), ConstrainedValue::Field(_field) => Type::Field, ConstrainedValue::Group(_group) => Type::Group, ConstrainedValue::Boolean(_bool) => Type::Boolean, - _ => unimplemented!("to type only implemented for primitives"), - } + ConstrainedValue::Array(types) => { + let array_type = types[0].to_type(span.clone())?; + let count = types.len(); + + // nested array type + if let Type::Array(inner_type, inner_dimensions) = &array_type { + let mut dimensions = inner_dimensions.clone(); + dimensions.push(count); + return Ok(Type::Array(inner_type.clone(), dimensions)); + } + + Type::Array(Box::new(array_type), vec![count]) + } + ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.clone()), + value => return Err(ValueError::implicit(value.to_string(), span)), + }) } - pub(crate) fn resolve_type(&mut self, types: &Vec) -> Result<(), ValueError> { + pub(crate) fn resolve_type(&mut self, types: &Vec, span: Span) -> Result<(), ValueError> { if let ConstrainedValue::Unresolved(ref string) = self { if !types.is_empty() { - *self = ConstrainedValue::from_type(string.clone(), &types[0])? + *self = ConstrainedValue::from_type(string.clone(), &types[0], span)? } } @@ -87,16 +101,16 @@ impl> ConstrainedValue { } /// Expect both `self` and `other` to resolve to the same type - pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec) -> Result<(), ValueError> { + pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec, span: Span) -> Result<(), ValueError> { if !types.is_empty() { - self.resolve_type(types)?; - return other.resolve_type(types); + self.resolve_type(types, span.clone())?; + return other.resolve_type(types, span); } match (&self, &other) { (ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()), - (ConstrainedValue::Unresolved(_), _) => self.resolve_type(&vec![other.to_type()]), - (_, ConstrainedValue::Unresolved(_)) => other.resolve_type(&vec![self.to_type()]), + (ConstrainedValue::Unresolved(_), _) => self.resolve_type(&vec![other.to_type(span.clone())?], span), + (_, ConstrainedValue::Unresolved(_)) => other.resolve_type(&vec![self.to_type(span.clone())?], span), _ => Ok(()), } } @@ -107,37 +121,44 @@ impl> ConstrainedValue { } } - pub(crate) fn allocate_value>(&mut self, mut cs: CS) -> Result<(), ValueError> { + pub(crate) fn allocate_value>(&mut self, mut cs: CS, span: Span) -> Result<(), ValueError> { match self { // allocated values ConstrainedValue::Boolean(boolean) => { let option = boolean.get_value(); + let name = option.map(|b| b.to_string()).unwrap_or(format!("[allocated]")); - *boolean = Boolean::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; + *boolean = allocate_bool(&mut cs, name, option, span)?; } ConstrainedValue::Integer(integer) => { let integer_type = integer.get_type(); let option = integer.get_value(); - let name = format!("clone {}", integer); + let name = option.map(|n| n.to_string()).unwrap_or(format!("[allocated]")); - *integer = Integer::allocate_type(&mut cs, integer_type, name, option)?; + *integer = Integer::allocate_type(&mut cs, integer_type, name, option, span)?; } ConstrainedValue::Field(field) => { let option = field.get_value().map(|v| format!("{}", v)); + let name = option.clone().map(|f| f.to_string()).unwrap_or(format!("[allocated]")); - *field = FieldType::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; + *field = allocate_field(&mut cs, name, option, span)?; } ConstrainedValue::Group(group) => { - let string = format!("{}", group); // may need to implement u256 -> decimal formatting + let name = format!("{}", group); // may need to implement u256 -> decimal formatting + let option = Some(name.clone()); - *group = G::alloc(cs, || Ok(string))?; + *group = allocate_group(&mut cs, name, option, span)?; } // value wrappers ConstrainedValue::Array(array) => { array .iter_mut() .enumerate() - .map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate array member {}", i)))) + .map(|(i, value)| { + let unique_name = format!("allocate array member {} {}:{}", i, span.line, span.start); + + value.allocate_value(cs.ns(|| unique_name), span.clone()) + }) .collect::>()?; } ConstrainedValue::CircuitExpression(_id, members) => { @@ -145,9 +166,9 @@ impl> ConstrainedValue { .iter_mut() .enumerate() .map(|(i, member)| { - member - .1 - .allocate_value(cs.ns(|| format!("allocate circuit member {}", i))) + let unique_name = format!("allocate circuit member {} {}:{}", i, span.line, span.start); + + member.1.allocate_value(cs.ns(|| unique_name), span.clone()) }) .collect::>()?; } @@ -155,20 +176,24 @@ impl> ConstrainedValue { array .iter_mut() .enumerate() - .map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate return member {}", i)))) + .map(|(i, value)| { + let unique_name = format!("allocate return member {} {}:{}", i, span.line, span.start); + + value.allocate_value(cs.ns(|| unique_name), span.clone()) + }) .collect::>()?; } ConstrainedValue::Mutable(value) => { - value.allocate_value(cs)?; + value.allocate_value(cs, span)?; } ConstrainedValue::Static(value) => { - value.allocate_value(cs)?; + value.allocate_value(cs, span)?; } // empty wrappers ConstrainedValue::CircuitDefinition(_) => {} ConstrainedValue::Function(_, _) => {} - ConstrainedValue::Unresolved(_) => { - return Err(ValueError::SynthesisError(SynthesisError::AssignmentMissing)); + ConstrainedValue::Unresolved(value) => { + return Err(ValueError::implicit(value.to_string(), span)); } } @@ -182,7 +207,14 @@ impl> fmt::Display for ConstrainedValue write!(f, "{}", value), ConstrainedValue::Field(ref value) => write!(f, "{:?}", value), ConstrainedValue::Group(ref value) => write!(f, "{:?}", value), - ConstrainedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()), + ConstrainedValue::Boolean(ref value) => write!( + f, + "{}", + value + .get_value() + .map(|v| v.to_string()) + .unwrap_or(format!("[allocated]")) + ), ConstrainedValue::Array(ref array) => { write!(f, "[")?; for (i, e) in array.iter().enumerate() { @@ -213,10 +245,10 @@ impl> fmt::Display for ConstrainedValue { - unimplemented!("cannot return circuit definition in program") + ConstrainedValue::CircuitDefinition(ref circuit) => write!(f, "circuit {{ {} }}", circuit.circuit_name), + ConstrainedValue::Function(ref _circuit_option, ref function) => { + write!(f, "function {{ {}() }}", function.function_name) } - ConstrainedValue::Function(ref _circuit_option, ref function) => write!(f, "{}", function), ConstrainedValue::Mutable(ref value) => write!(f, "mut {}", value), ConstrainedValue::Static(ref value) => write!(f, "static {}", value), ConstrainedValue::Unresolved(ref value) => write!(f, "unresolved {}", value), @@ -238,33 +270,21 @@ impl> ConditionalEqGadget for Constrai condition: &Boolean, ) -> Result<(), SynthesisError> { match (self, other) { - (ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => bool_1.conditional_enforce_equal( - cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())), - bool_2, - &condition, - ), - (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => num_1.conditional_enforce_equal( - cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())), - num_2, - &condition, - ), - (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => field_1.conditional_enforce_equal( - cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())), - field_2, - &condition, - ), - (ConstrainedValue::Group(group_1), ConstrainedValue::Group(group_2)) => group_1.conditional_enforce_equal( - cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())), - group_2, - &condition, - ), + (ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => { + bool_1.conditional_enforce_equal(cs, bool_2, &condition) + } + (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { + num_1.conditional_enforce_equal(cs, num_2, &condition) + } + (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { + field_1.conditional_enforce_equal(cs, field_2, &condition) + } + (ConstrainedValue::Group(group_1), ConstrainedValue::Group(group_2)) => { + group_1.conditional_enforce_equal(cs, group_2, &condition) + } (ConstrainedValue::Array(arr_1), ConstrainedValue::Array(arr_2)) => { for (i, (left, right)) in arr_1.into_iter().zip(arr_2.into_iter()).enumerate() { - left.conditional_enforce_equal( - cs.ns(|| format!("array[{}] equal {} == {}", i, left.to_string(), right.to_string())), - right, - &condition, - )?; + left.conditional_enforce_equal(cs.ns(|| format!("array[{}]", i)), right, &condition)?; } Ok(()) } @@ -286,49 +306,22 @@ impl> CondSelectGadget for Constrained ) -> Result { Ok(match (first, second) { (ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => { - ConstrainedValue::Boolean(Boolean::conditionally_select( - cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())), - cond, - bool_1, - bool_2, - )?) + ConstrainedValue::Boolean(Boolean::conditionally_select(cs, cond, bool_1, bool_2)?) } (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - ConstrainedValue::Integer(Integer::conditionally_select( - cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())), - cond, - num_1, - num_2, - )?) + ConstrainedValue::Integer(Integer::conditionally_select(cs, cond, num_1, num_2)?) } (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { - ConstrainedValue::Field(FieldType::conditionally_select( - cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())), - cond, - field_1, - field_2, - )?) + ConstrainedValue::Field(FieldType::conditionally_select(cs, cond, field_1, field_2)?) } (ConstrainedValue::Group(group_1), ConstrainedValue::Group(group_2)) => { - ConstrainedValue::Group(G::conditionally_select( - cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())), - cond, - group_1, - group_2, - )?) + ConstrainedValue::Group(G::conditionally_select(cs, cond, group_1, group_2)?) } (ConstrainedValue::Array(arr_1), ConstrainedValue::Array(arr_2)) => { let mut array = vec![]; for (i, (first, second)) in arr_1.into_iter().zip(arr_2.into_iter()).enumerate() { array.push(Self::conditionally_select( - cs.ns(|| { - format!( - "array[{}] = if cond ? {} else {}", - i, - first.to_string(), - second.to_string() - ) - }), + cs.ns(|| format!("array[{}]", i,)), cond, first, second, @@ -336,6 +329,8 @@ impl> CondSelectGadget for Constrained } ConstrainedValue::Array(array) } + (ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?, + (_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?, (_, _) => return Err(SynthesisError::Unsatisfiable), }) } diff --git a/compiler/src/errors/compiler.rs b/compiler/src/errors/compiler.rs index d6ee381509..90ba339810 100644 --- a/compiler/src/errors/compiler.rs +++ b/compiler/src/errors/compiler.rs @@ -1,51 +1,38 @@ use crate::errors::{FunctionError, ImportError}; -use leo_ast::{ParserError, SyntaxError}; +use leo_ast::ParserError; use leo_inputs::InputParserError; -use leo_types::IntegerError; -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum CompilerError { - #[error("creating: {}", _0)] - Creating(io::Error), - - #[error("Attempt to access current directory failed - {:?}", _0)] - DirectoryError(io::Error), - #[error("{}", _0)] ImportError(#[from] ImportError), #[error("{}", _0)] InputParserError(#[from] InputParserError), - #[error("{}", _0)] - IntegerError(#[from] IntegerError), - #[error("{}", _0)] FunctionError(#[from] FunctionError), #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), - #[error("Syntax error. Cannot parse the file")] - FileParsingError, - - #[error("Main function not found")] + #[error("`main` function not found")] NoMain, - #[error("Main must be a function")] + #[error("`main` must be a function")] NoMainFunction, #[error("{}", _0)] ParserError(#[from] ParserError), - - #[error("{}", _0)] - SyntaxError(#[from] SyntaxError), - - #[error("Unable to construct abstract syntax tree")] - SyntaxTreeError, - - #[error("writing: {}", _0)] - Writing(io::Error), +} + +impl CompilerError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + CompilerError::FunctionError(error) => error.set_path(path), + _ => {} + } + } } diff --git a/compiler/src/errors/constraints/boolean.rs b/compiler/src/errors/constraints/boolean.rs index 24e4ed0088..bea08d67e4 100644 --- a/compiler/src/errors/constraints/boolean.rs +++ b/compiler/src/errors/constraints/boolean.rs @@ -1,18 +1,49 @@ -use snarkos_errors::gadgets::SynthesisError; +use leo_types::{Error as FormattedError, Span}; -use std::str::ParseBoolError; +use snarkos_errors::gadgets::SynthesisError; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum BooleanError { - #[error("Cannot evaluate {}", _0)] - CannotEvaluate(String), - - #[error("Cannot enforce {}", _0)] - CannotEnforce(String), - #[error("{}", _0)] - ParseBoolError(#[from] ParseBoolError), - - #[error("{}", _0)] - SynthesisError(#[from] SynthesisError), + Error(#[from] FormattedError), +} + +impl BooleanError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + BooleanError::Error(error) => error.set_path(path), + } + } + + fn new_from_span(message: String, span: Span) -> Self { + BooleanError::Error(FormattedError::new_from_span(message, span)) + } + + pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self { + let message = format!( + "the boolean operation `{}` failed due to the synthesis error `{}`", + operation, error, + ); + + Self::new_from_span(message, span) + } + + pub fn cannot_evaluate(operation: String, span: Span) -> Self { + let message = format!("no implementation found for `{}`", operation); + + Self::new_from_span(message, span) + } + + pub fn invalid_boolean(actual: String, span: Span) -> Self { + let message = format!("expected boolean input type, found `{}`", actual); + + Self::new_from_span(message, span) + } + + pub fn missing_boolean(expected: String, span: Span) -> Self { + let message = format!("expected boolean input `{}` not found", expected); + + Self::new_from_span(message, span) + } } diff --git a/compiler/src/errors/constraints/expression.rs b/compiler/src/errors/constraints/expression.rs index 3b1a487755..630602f482 100644 --- a/compiler/src/errors/constraints/expression.rs +++ b/compiler/src/errors/constraints/expression.rs @@ -1,8 +1,8 @@ -use crate::errors::{BooleanError, Error as FormattedError, FieldError, FunctionError, GroupError, ValueError}; -use leo_types::{Identifier, IntegerError, Span}; +use crate::errors::{BooleanError, FieldError, FunctionError, GroupError, ValueError}; +use leo_types::{Error as FormattedError, Identifier, IntegerError, Span}; use snarkos_errors::gadgets::SynthesisError; -use std::num::ParseIntError; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum ExpressionError { @@ -12,9 +12,6 @@ pub enum ExpressionError { #[error("{}", _0)] Error(#[from] FormattedError), - #[error("{}", _0)] - IntegerError(#[from] IntegerError), - #[error("{}", _0)] FieldError(#[from] FieldError), @@ -25,28 +22,46 @@ pub enum ExpressionError { GroupError(#[from] GroupError), #[error("{}", _0)] - ParseIntError(#[from] ParseIntError), - - #[error("{}", _0)] - SynthesisError(#[from] SynthesisError), + IntegerError(#[from] IntegerError), #[error("{}", _0)] ValueError(#[from] ValueError), } impl ExpressionError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + ExpressionError::BooleanError(error) => error.set_path(path), + ExpressionError::Error(error) => error.set_path(path), + ExpressionError::FieldError(error) => error.set_path(path), + ExpressionError::FunctionError(error) => error.set_path(path), + ExpressionError::GroupError(error) => error.set_path(path), + ExpressionError::IntegerError(error) => error.set_path(path), + ExpressionError::ValueError(error) => error.set_path(path), + } + } + fn new_from_span(message: String, span: Span) -> Self { ExpressionError::Error(FormattedError::new_from_span(message, span)) } + pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self { + let message = format!( + "the gadget operation `{}` failed due to synthesis error `{}`", + operation, error, + ); + + Self::new_from_span(message, span) + } + pub fn conditional_boolean(actual: String, span: Span) -> Self { - let message = format!("If, else conditional must resolve to a boolean, found `{}`", actual); + let message = format!("if, else conditional must resolve to a boolean, found `{}`", actual); Self::new_from_span(message, span) } pub fn expected_circuit_member(expected: String, span: Span) -> Self { - let message = format!("Expected circuit member `{}`, not found", expected); + let message = format!("expected circuit member `{}`, not found", expected); Self::new_from_span(message, span) } @@ -64,50 +79,50 @@ impl ExpressionError { } pub fn invalid_index(actual: String, span: Span) -> Self { - let message = format!("Index must resolve to an integer, found `{}`", actual); + let message = format!("index must resolve to an integer, found `{}`", actual); Self::new_from_span(message, span) } pub fn invalid_length(expected: usize, actual: usize, span: Span) -> Self { - let message = format!("Expected array length {}, found one with length {}", expected, actual); + let message = format!("expected array length {}, found one with length {}", expected, actual); Self::new_from_span(message, span) } pub fn invalid_spread(actual: String, span: Span) -> Self { - let message = format!("Spread should contain an array, found `{}`", actual); + let message = format!("spread should contain an array, found `{}`", actual); Self::new_from_span(message, span) } pub fn invalid_member_access(member: String, span: Span) -> Self { - let message = format!("Non-static member `{}` must be accessed using `.` syntax", member); + let message = format!("non-static member `{}` must be accessed using `.` syntax", member); Self::new_from_span(message, span) } pub fn invalid_static_access(member: String, span: Span) -> Self { - let message = format!("Static member `{}` must be accessed using `::` syntax", member); + let message = format!("static member `{}` must be accessed using `::` syntax", member); Self::new_from_span(message, span) } pub fn function_no_return(function: String, span: Span) -> Self { - let message = format!("Inline function call to `{}` did not return", function); + let message = format!("inline function call to `{}` did not return", function); Self::new_from_span(message, span) } pub fn undefined_array(actual: String, span: Span) -> Self { - let message = format!("Array `{}` must be declared before it is used in an expression", actual); + let message = format!("array `{}` must be declared before it is used in an expression", actual); Self::new_from_span(message, span) } pub fn undefined_circuit(actual: String, span: Span) -> Self { let message = format!( - "Circuit `{}` must be declared before it is used in an expression", + "circuit `{}` must be declared before it is used in an expression", actual ); @@ -122,7 +137,7 @@ impl ExpressionError { pub fn undefined_function(function: String, span: Span) -> Self { let message = format!( - "Function `{}` must be declared before it is used in an inline expression", + "function `{}` must be declared before it is used in an inline expression", function ); diff --git a/compiler/src/errors/constraints/field.rs b/compiler/src/errors/constraints/field.rs index 87874b4e5b..05e1d2f437 100644 --- a/compiler/src/errors/constraints/field.rs +++ b/compiler/src/errors/constraints/field.rs @@ -1,13 +1,49 @@ +use leo_types::{Error as FormattedError, Span}; + use snarkos_errors::gadgets::SynthesisError; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum FieldError { - #[error("Expected field element parameter, got {}", _0)] - Invalid(String), - - #[error("No multiplicative inverse found for field {}", _0)] - NoInverse(String), - #[error("{}", _0)] - SynthesisError(#[from] SynthesisError), + Error(#[from] FormattedError), +} + +impl FieldError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + FieldError::Error(error) => error.set_path(path), + } + } + + fn new_from_span(message: String, span: Span) -> Self { + FieldError::Error(FormattedError::new_from_span(message, span)) + } + + pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self { + let message = format!( + "the field binary operation `{}` failed due to synthesis error `{}`", + operation, error, + ); + + Self::new_from_span(message, span) + } + + pub fn invalid_field(actual: String, span: Span) -> Self { + let message = format!("expected field element input type, found `{}`", actual); + + Self::new_from_span(message, span) + } + + pub fn missing_field(expected: String, span: Span) -> Self { + let message = format!("expected integer input `{}` not found", expected); + + Self::new_from_span(message, span) + } + + pub fn no_inverse(field: String, span: Span) -> Self { + let message = format!("no multiplicative inverse found for field `{}`", field); + + Self::new_from_span(message, span) + } } diff --git a/compiler/src/errors/constraints/function.rs b/compiler/src/errors/constraints/function.rs index adf05e0c74..6c7a269bf2 100644 --- a/compiler/src/errors/constraints/function.rs +++ b/compiler/src/errors/constraints/function.rs @@ -1,13 +1,6 @@ -use crate::errors::{ - BooleanError, - Error as FormattedError, - ExpressionError, - FieldError, - GroupError, - StatementError, - ValueError, -}; -use leo_types::{IntegerError, Span}; +use crate::errors::{BooleanError, ExpressionError, FieldError, GroupError, StatementError, ValueError}; +use leo_types::{Error as FormattedError, IntegerError, Span}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum FunctionError { @@ -37,6 +30,19 @@ pub enum FunctionError { } impl FunctionError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + FunctionError::BooleanError(error) => error.set_path(path), + FunctionError::ExpressionError(error) => error.set_path(path), + FunctionError::Error(error) => error.set_path(path), + FunctionError::FieldError(error) => error.set_path(path), + FunctionError::GroupError(error) => error.set_path(path), + FunctionError::IntegerError(error) => error.set_path(path), + FunctionError::StatementError(error) => error.set_path(path), + FunctionError::ValueError(error) => error.set_path(path), + } + } + fn new_from_span(message: String, span: Span) -> Self { FunctionError::Error(FormattedError::new_from_span(message, span)) } diff --git a/compiler/src/errors/constraints/group.rs b/compiler/src/errors/constraints/group.rs index fc84a62e37..5e7fdcefd6 100644 --- a/compiler/src/errors/constraints/group.rs +++ b/compiler/src/errors/constraints/group.rs @@ -1,10 +1,43 @@ +use leo_types::{Error as FormattedError, Span}; + use snarkos_errors::gadgets::SynthesisError; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum GroupError { - #[error("Expected affine point, got {}", _0)] - Invalid(String), - #[error("{}", _0)] - SynthesisError(#[from] SynthesisError), + Error(#[from] FormattedError), +} + +impl GroupError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + GroupError::Error(error) => error.set_path(path), + } + } + + fn new_from_span(message: String, span: Span) -> Self { + GroupError::Error(FormattedError::new_from_span(message, span)) + } + + pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self { + let message = format!( + "the group binary operation `{}` failed due to the synthesis error `{}`", + operation, error, + ); + + Self::new_from_span(message, span) + } + + pub fn invalid_group(actual: String, span: Span) -> Self { + let message = format!("expected group affine point input type, found `{}`", actual); + + Self::new_from_span(message, span) + } + + pub fn missing_group(expected: String, span: Span) -> Self { + let message = format!("expected group input `{}` not found", expected); + + Self::new_from_span(message, span) + } } diff --git a/compiler/src/errors/constraints/import.rs b/compiler/src/errors/constraints/import.rs index 1d442ec361..c5d3c238d9 100644 --- a/compiler/src/errors/constraints/import.rs +++ b/compiler/src/errors/constraints/import.rs @@ -1,21 +1,34 @@ use leo_ast::ParserError; +use leo_types::{Error as FormattedError, ImportSymbol, Span}; use std::{io, path::PathBuf}; #[derive(Debug, Error)] pub enum ImportError { - #[error("Attempt to access current directory failed - {:?}", _0)] - DirectoryError(io::Error), - - #[error("Syntax error. Cannot parse the file")] - FileParsingError, - - #[error("Cannot read from the provided file path - {:?}", _0)] - FileReadError(PathBuf), + #[error("{}", _0)] + Error(#[from] FormattedError), #[error("{}", _0)] ParserError(#[from] ParserError), - - #[error("Unable to construct abstract syntax tree")] - SyntaxTreeError, +} + +impl ImportError { + fn new_from_span(message: String, span: Span) -> Self { + ImportError::Error(FormattedError::new_from_span(message, span)) + } + + pub fn directory_error(error: io::Error, span: Span) -> Self { + let message = format!("attempt to access current directory failed - {:?}", error); + + Self::new_from_span(message, span) + } + + pub fn unknown_symbol(symbol: ImportSymbol, file: String, file_path: &PathBuf) -> Self { + let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file); + let mut error = FormattedError::new_from_span(message, symbol.span); + + error.path = Some(format!("{:?}", file_path)); + + ImportError::Error(error) + } } diff --git a/compiler/src/errors/constraints/statement.rs b/compiler/src/errors/constraints/statement.rs index 863508fa89..4c69fcb31f 100644 --- a/compiler/src/errors/constraints/statement.rs +++ b/compiler/src/errors/constraints/statement.rs @@ -1,31 +1,46 @@ -use crate::errors::{BooleanError, Error as FormattedError, ExpressionError, ValueError}; -use leo_types::Span; - -use snarkos_errors::gadgets::SynthesisError; +use crate::errors::{BooleanError, ExpressionError, ValueError}; +use leo_types::{Error as FormattedError, IntegerError, Span, Type}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum StatementError { #[error("{}", _0)] - Error(#[from] FormattedError), + BooleanError(#[from] BooleanError), #[error("{}", _0)] - BooleanError(#[from] BooleanError), + Error(#[from] FormattedError), #[error("{}", _0)] ExpressionError(#[from] ExpressionError), #[error("{}", _0)] - SynthesisError(#[from] SynthesisError), + IntegerError(#[from] IntegerError), #[error("{}", _0)] ValueError(#[from] ValueError), } impl StatementError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + StatementError::BooleanError(error) => error.set_path(path), + StatementError::Error(error) => error.set_path(path), + StatementError::ExpressionError(error) => error.set_path(path), + StatementError::IntegerError(error) => error.set_path(path), + StatementError::ValueError(error) => error.set_path(path), + } + } + fn new_from_span(message: String, span: Span) -> Self { StatementError::Error(FormattedError::new_from_span(message, span)) } + pub fn arguments_type(expected: &Type, actual: &Type, span: Span) -> Self { + let message = format!("expected return argument type `{}`, found type `{}`", expected, actual); + + Self::new_from_span(message, span) + } + pub fn array_assign_index(span: Span) -> Self { let message = format!("Cannot assign single index to array of values"); @@ -50,6 +65,27 @@ impl StatementError { Self::new_from_span(message, span) } + pub fn immutable_assign(name: String, span: Span) -> Self { + let message = format!("Cannot assign to immutable variable `{}`", name); + + Self::new_from_span(message, span) + } + + pub fn immutable_circuit_function(name: String, span: Span) -> Self { + let message = format!("Cannot mutate circuit function, `{}`", name); + + Self::new_from_span(message, span) + } + + pub fn indicator_calculation(name: String, span: Span) -> Self { + let message = format!( + "Constraint system failed to evaluate branch selection indicator `{}`", + name + ); + + Self::new_from_span(message, span) + } + pub fn invalid_number_of_definitions(expected: usize, actual: usize, span: Span) -> Self { let message = format!( "Multiple definition statement expected {} return values, found {} values", @@ -68,18 +104,6 @@ impl StatementError { Self::new_from_span(message, span) } - pub fn immutable_assign(name: String, span: Span) -> Self { - let message = format!("Cannot assign to immutable variable `{}`", name); - - Self::new_from_span(message, span) - } - - pub fn immutable_circuit_function(name: String, span: Span) -> Self { - let message = format!("Cannot mutate circuit function, `{}`", name); - - Self::new_from_span(message, span) - } - pub fn select_fail(first: String, second: String, span: Span) -> Self { let message = format!( "Conditional select gadget failed to select between `{}` or `{}`", diff --git a/compiler/src/errors/constraints/value.rs b/compiler/src/errors/constraints/value.rs index b8eda405df..43504c144b 100644 --- a/compiler/src/errors/constraints/value.rs +++ b/compiler/src/errors/constraints/value.rs @@ -1,11 +1,15 @@ -use crate::errors::{FieldError, GroupError}; -use leo_types::IntegerError; - -use snarkos_errors::gadgets::SynthesisError; -use std::{num::ParseIntError, str::ParseBoolError}; +use crate::errors::{BooleanError, FieldError, GroupError}; +use leo_types::{Error as FormattedError, IntegerError, Span}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum ValueError { + #[error("{}", _0)] + BooleanError(#[from] BooleanError), + + #[error("{}", _0)] + Error(#[from] FormattedError), + #[error("{}", _0)] FieldError(#[from] FieldError), @@ -14,13 +18,26 @@ pub enum ValueError { #[error("{}", _0)] IntegerError(#[from] IntegerError), - - #[error("{}", _0)] - ParseBoolError(#[from] ParseBoolError), - - #[error("{}", _0)] - ParseIntError(#[from] ParseIntError), - - #[error("{}", _0)] - SynthesisError(#[from] SynthesisError), +} + +impl ValueError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + ValueError::BooleanError(error) => error.set_path(path), + ValueError::Error(error) => error.set_path(path), + ValueError::FieldError(error) => error.set_path(path), + ValueError::GroupError(error) => error.set_path(path), + ValueError::IntegerError(error) => error.set_path(path), + } + } + + fn new_from_span(message: String, span: Span) -> Self { + ValueError::Error(FormattedError::new_from_span(message, span)) + } + + pub fn implicit(value: String, span: Span) -> Self { + let message = format!("explicit type needed for `{}`", value); + + Self::new_from_span(message, span) + } } diff --git a/compiler/src/errors/mod.rs b/compiler/src/errors/mod.rs index 0b00c97e75..91d6712541 100644 --- a/compiler/src/errors/mod.rs +++ b/compiler/src/errors/mod.rs @@ -3,6 +3,3 @@ pub use self::compiler::*; pub mod constraints; pub use self::constraints::*; - -pub mod error; -pub use self::error::*; diff --git a/compiler/src/field/mod.rs b/compiler/src/field/mod.rs index b7a455b1f2..cef4cfec77 100644 --- a/compiler/src/field/mod.rs +++ b/compiler/src/field/mod.rs @@ -1,6 +1,7 @@ //! A data type that represents a field value use crate::errors::FieldError; +use leo_types::Span; use snarkos_errors::gadgets::SynthesisError; use snarkos_models::{ @@ -35,82 +36,100 @@ impl FieldType { } } - pub fn constant(string: String) -> Result { - let value = F::from_str(&string).map_err(|_| FieldError::Invalid(string))?; + pub fn constant(string: String, span: Span) -> Result { + let value = F::from_str(&string).map_err(|_| FieldError::invalid_field(string, span))?; Ok(FieldType::Constant(value)) } - pub fn add>(&self, cs: CS, other: &Self) -> Result { + pub fn add>(&self, cs: CS, other: &Self, span: Span) -> Result { match (self, other) { (FieldType::Constant(self_value), FieldType::Constant(other_value)) => { Ok(FieldType::Constant(self_value.add(other_value))) } (FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => { - let result = self_value.add(cs, other_value)?; - - Ok(FieldType::Allocated(result)) - } - - (FieldType::Constant(constant_value), FieldType::Allocated(allocated_value)) - | (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => { - Ok(FieldType::Allocated(allocated_value.add_constant(cs, constant_value)?)) - } - } - } - - pub fn sub>(&self, cs: CS, other: &Self) -> Result { - match (self, other) { - (FieldType::Constant(self_value), FieldType::Constant(other_value)) => { - Ok(FieldType::Constant(self_value.sub(other_value))) - } - - (FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => { - let result = self_value.sub(cs, other_value)?; - - Ok(FieldType::Allocated(result)) - } - - (FieldType::Constant(constant_value), FieldType::Allocated(allocated_value)) - | (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => { - Ok(FieldType::Allocated(allocated_value.sub_constant(cs, constant_value)?)) - } - } - } - - pub fn mul>(&self, cs: CS, other: &Self) -> Result { - match (self, other) { - (FieldType::Constant(self_value), FieldType::Constant(other_value)) => { - Ok(FieldType::Constant(self_value.mul(other_value))) - } - - (FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => { - let result = self_value.mul(cs, other_value)?; + let result = self_value + .add(cs, other_value) + .map_err(|e| FieldError::cannot_enforce(format!("+"), e, span))?; Ok(FieldType::Allocated(result)) } (FieldType::Constant(constant_value), FieldType::Allocated(allocated_value)) | (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(FieldType::Allocated( - allocated_value.mul_by_constant(cs, constant_value)?, + allocated_value + .add_constant(cs, constant_value) + .map_err(|e| FieldError::cannot_enforce(format!("+"), e, span))?, )), } } - pub fn div>(&self, mut cs: CS, other: &Self) -> Result { + pub fn sub>(&self, cs: CS, other: &Self, span: Span) -> Result { + match (self, other) { + (FieldType::Constant(self_value), FieldType::Constant(other_value)) => { + Ok(FieldType::Constant(self_value.sub(other_value))) + } + + (FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => { + let result = self_value + .sub(cs, other_value) + .map_err(|e| FieldError::cannot_enforce(format!("-"), e, span))?; + + Ok(FieldType::Allocated(result)) + } + + (FieldType::Constant(constant_value), FieldType::Allocated(allocated_value)) + | (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(FieldType::Allocated( + allocated_value + .sub_constant(cs, constant_value) + .map_err(|e| FieldError::cannot_enforce(format!("+"), e, span))?, + )), + } + } + + pub fn mul>(&self, cs: CS, other: &Self, span: Span) -> Result { + match (self, other) { + (FieldType::Constant(self_value), FieldType::Constant(other_value)) => { + Ok(FieldType::Constant(self_value.mul(other_value))) + } + + (FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => { + let result = self_value + .mul(cs, other_value) + .map_err(|e| FieldError::cannot_enforce(format!("*"), e, span))?; + + Ok(FieldType::Allocated(result)) + } + + (FieldType::Constant(constant_value), FieldType::Allocated(allocated_value)) + | (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(FieldType::Allocated( + allocated_value + .mul_by_constant(cs, constant_value) + .map_err(|e| FieldError::cannot_enforce(format!("*"), e, span))?, + )), + } + } + + pub fn div>(&self, mut cs: CS, other: &Self, span: Span) -> Result { let inverse = match other { FieldType::Constant(constant) => { - let constant_inverse = constant.inverse().ok_or(FieldError::NoInverse(constant.to_string()))?; + let constant_inverse = constant + .inverse() + .ok_or(FieldError::no_inverse(constant.to_string(), span.clone()))?; + FieldType::Constant(constant_inverse) } FieldType::Allocated(allocated) => { - let allocated_inverse = allocated.inverse(&mut cs)?; + let allocated_inverse = allocated + .inverse(&mut cs) + .map_err(|e| FieldError::cannot_enforce(format!("+"), e, span.clone()))?; + FieldType::Allocated(allocated_inverse) } }; - self.mul(cs, &inverse) + self.mul(cs, &inverse, span) } pub fn alloc_helper Result, T: Borrow>( diff --git a/compiler/src/group/edwards_bls12.rs b/compiler/src/group/edwards_bls12.rs index 34ad793900..c6467639e4 100644 --- a/compiler/src/group/edwards_bls12.rs +++ b/compiler/src/group/edwards_bls12.rs @@ -1,4 +1,5 @@ use crate::{errors::GroupError, GroupType}; +use leo_types::Span; use snarkos_curves::{ edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq}, @@ -31,13 +32,14 @@ pub enum EdwardsGroupType { } impl GroupType for EdwardsGroupType { - fn constant(string: String) -> Result { - let value = Self::edwards_affine_from_str(string)?; + fn constant(string: String, span: Span) -> Result { + let value = + Self::edwards_affine_from_str(string.clone()).map_err(|_| GroupError::invalid_group(string, span))?; Ok(EdwardsGroupType::Constant(value)) } - fn add>(&self, cs: CS, other: &Self) -> Result { + fn add>(&self, cs: CS, other: &Self, span: Span) -> Result { match (self, other) { (EdwardsGroupType::Constant(self_value), EdwardsGroupType::Constant(other_value)) => { Ok(EdwardsGroupType::Constant(self_value.add(other_value))) @@ -48,18 +50,24 @@ impl GroupType for EdwardsGroupType { self_value, cs, other_value, - )?; + ) + .map_err(|e| GroupError::cannot_enforce(format!("+"), e, span))?; + Ok(EdwardsGroupType::Allocated(result)) } (EdwardsGroupType::Constant(constant_value), EdwardsGroupType::Allocated(allocated_value)) - | (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => Ok( - EdwardsGroupType::Allocated(allocated_value.add_constant(cs, constant_value)?), - ), + | (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => { + Ok(EdwardsGroupType::Allocated( + allocated_value + .add_constant(cs, constant_value) + .map_err(|e| GroupError::cannot_enforce(format!("+"), e, span))?, + )) + } } } - fn sub>(&self, cs: CS, other: &Self) -> Result { + fn sub>(&self, cs: CS, other: &Self, span: Span) -> Result { match (self, other) { (EdwardsGroupType::Constant(self_value), EdwardsGroupType::Constant(other_value)) => { Ok(EdwardsGroupType::Constant(self_value.sub(other_value))) @@ -70,24 +78,30 @@ impl GroupType for EdwardsGroupType { self_value, cs, other_value, - )?; + ) + .map_err(|e| GroupError::cannot_enforce(format!("-"), e, span))?; + Ok(EdwardsGroupType::Allocated(result)) } (EdwardsGroupType::Constant(constant_value), EdwardsGroupType::Allocated(allocated_value)) - | (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => Ok( - EdwardsGroupType::Allocated(allocated_value.sub_constant(cs, constant_value)?), - ), + | (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => { + Ok(EdwardsGroupType::Allocated( + allocated_value + .sub_constant(cs, constant_value) + .map_err(|e| GroupError::cannot_enforce(format!("-"), e, span))?, + )) + } } } } impl EdwardsGroupType { - pub fn edwards_affine_from_str(string: String) -> Result { + pub fn edwards_affine_from_str(string: String) -> Result { // 0 or (0, 1) match Fq::from_str(&string).ok() { - Some(x) => EdwardsAffine::get_point_from_x(x, false).ok_or(GroupError::Invalid(string)), - None => EdwardsAffine::from_str(&string).map_err(|_| GroupError::Invalid(string)), + Some(x) => EdwardsAffine::get_point_from_x(x, false).ok_or(SynthesisError::AssignmentMissing), + None => EdwardsAffine::from_str(&string).map_err(|_| SynthesisError::AssignmentMissing), } } @@ -102,7 +116,7 @@ impl EdwardsGroupType { _ => Err(SynthesisError::AssignmentMissing), }?; - Self::edwards_affine_from_str(affine_string).map_err(|_| SynthesisError::AssignmentMissing) + Self::edwards_affine_from_str(affine_string) } pub fn allocated>(&self, mut cs: CS) -> Result { diff --git a/compiler/src/group/mod.rs b/compiler/src/group/mod.rs index 6af5532570..5ff7c8aefb 100644 --- a/compiler/src/group/mod.rs +++ b/compiler/src/group/mod.rs @@ -1,6 +1,7 @@ //! A data type that represents members in the group formed by the set of affine points on a curve. use crate::errors::GroupError; +use leo_types::Span; use snarkos_models::{ curves::Field, @@ -32,9 +33,9 @@ pub trait GroupType: + ToBitsGadget + ToBytesGadget { - fn constant(string: String) -> Result; + fn constant(string: String, span: Span) -> Result; - fn add>(&self, cs: CS, other: &Self) -> Result; + fn add>(&self, cs: CS, other: &Self, span: Span) -> Result; - fn sub>(&self, cs: CS, other: &Self) -> Result; + fn sub>(&self, cs: CS, other: &Self, span: Span) -> Result; } diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index a1310e8eae..9e547f5d1b 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -1,10 +1,17 @@ -use crate::{get_error, get_output, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler}; +use crate::{ + get_error, + get_output, + integers::fail_integer, + parse_program, + EdwardsConstrainedValue, + EdwardsTestCompiler, +}; use leo_compiler::{ errors::{CompilerError, FunctionError}, ConstrainedValue, }; use leo_inputs::types::{IntegerType, U32Type}; -use leo_types::{InputValue, Integer, IntegerError}; +use leo_types::{InputValue, Integer}; use snarkos_models::gadgets::utilities::uint::UInt32; @@ -42,14 +49,7 @@ fn output_multi(program: EdwardsTestCompiler) { fn fail_array(program: EdwardsTestCompiler) { match get_error(program) { CompilerError::FunctionError(FunctionError::Error(_string)) => {} - error => panic!("Expected invalid array error, got {}", error), - } -} - -fn fail_synthesis(program: EdwardsTestCompiler) { - match get_error(program) { - CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::SynthesisError(_string))) => {} - error => panic!("Expected synthesis error, got {}", error), + error => panic!("Expected function error, found {}", error), } } @@ -128,5 +128,5 @@ fn test_input_field_none() { program.set_inputs(vec![None]); - fail_synthesis(program) + fail_integer(program) } diff --git a/compiler/tests/boolean/mod.rs b/compiler/tests/boolean/mod.rs index 87e236419a..fc849e6008 100644 --- a/compiler/tests/boolean/mod.rs +++ b/compiler/tests/boolean/mod.rs @@ -23,35 +23,19 @@ pub fn output_false(program: EdwardsTestCompiler) { output_expected_boolean(program, false) } -fn fail_evaluate(program: EdwardsTestCompiler) { - match get_error(program) { - CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError( - ExpressionError::BooleanError(BooleanError::CannotEvaluate(_string)), - ))) => {} - error => panic!("Expected evaluate error, got {}", error), - } -} - -fn fail_enforce(program: EdwardsTestCompiler) { - match get_error(program) { - CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError( - ExpressionError::BooleanError(BooleanError::CannotEnforce(_string)), - ))) => {} - error => panic!("Expected evaluate error, got {}", error), - } -} - fn fail_boolean(program: EdwardsTestCompiler) { match get_error(program) { - CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::SynthesisError(_))) => {} - error => panic!("Expected invalid boolean error, got {}", error), + CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::Error(_))) => {} + error => panic!("Expected boolean error, got {}", error), } } -fn fail_synthesis(program: EdwardsTestCompiler) { +fn fail_boolean_statement(program: EdwardsTestCompiler) { match get_error(program) { - CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::SynthesisError(_string))) => {} - error => panic!("Expected synthesis error, got {}", error), + CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError( + ExpressionError::BooleanError(BooleanError::Error(_)), + ))) => {} + _ => panic!("Expected boolean error, got {}"), } } @@ -88,7 +72,7 @@ fn test_input_bool_none() { program.set_inputs(vec![None]); - fail_synthesis(program); + fail_boolean(program); } // Boolean not ! @@ -114,7 +98,7 @@ fn test_not_u32() { let bytes = include_bytes!("not_u32.leo"); let program = parse_program(bytes).unwrap(); - fail_evaluate(program); + fail_boolean_statement(program) } // Boolean or || @@ -148,7 +132,7 @@ fn test_true_or_u32() { let bytes = include_bytes!("true_or_u32.leo"); let program = parse_program(bytes).unwrap(); - fail_enforce(program); + fail_boolean_statement(program); } // Boolean and && @@ -182,7 +166,7 @@ fn test_true_and_u32() { let bytes = include_bytes!("true_and_u32.leo"); let program = parse_program(bytes).unwrap(); - fail_enforce(program); + fail_boolean_statement(program); } // All diff --git a/compiler/tests/circuits/mod.rs b/compiler/tests/circuits/mod.rs index 20d6b5d429..74898407af 100644 --- a/compiler/tests/circuits/mod.rs +++ b/compiler/tests/circuits/mod.rs @@ -284,10 +284,12 @@ fn test_self() { // All -// #[test] -// fn test_pedersen_mock() { -// let bytes = include_bytes!("pedersen_mock.leo"); -// let program = parse_program(bytes).unwrap(); -// -// output_zero(program); -// } +#[test] +fn test_pedersen_mock() { + use crate::integers::u32::output_zero; + + let bytes = include_bytes!("pedersen_mock.leo"); + let program = parse_program(bytes).unwrap(); + + output_zero(program); +} diff --git a/compiler/tests/field/mod.rs b/compiler/tests/field/mod.rs index db3bf89491..77087b4abc 100644 --- a/compiler/tests/field/mod.rs +++ b/compiler/tests/field/mod.rs @@ -54,18 +54,11 @@ fn output_one(program: EdwardsTestCompiler) { fn fail_field(program: EdwardsTestCompiler) { match get_error(program) { - CompilerError::FunctionError(FunctionError::FieldError(FieldError::Invalid(_string))) => {} + CompilerError::FunctionError(FunctionError::FieldError(FieldError::Error(_string))) => {} error => panic!("Expected invalid field error, got {}", error), } } -fn fail_synthesis(program: EdwardsTestCompiler) { - match get_error(program) { - CompilerError::FunctionError(FunctionError::FieldError(FieldError::SynthesisError(_string))) => {} - error => panic!("Expected synthesis error, got {}", error), - } -} - #[test] fn test_zero() { let bytes = include_bytes!("zero.leo"); @@ -110,7 +103,7 @@ fn test_input_fail_none() { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![None]); - fail_synthesis(program); + fail_field(program); } #[test] diff --git a/compiler/tests/function/iteration.leo b/compiler/tests/function/iteration.leo new file mode 100644 index 0000000000..ef967c2b0a --- /dev/null +++ b/compiler/tests/function/iteration.leo @@ -0,0 +1,13 @@ +function one() -> u32 { + return 1u32 +} + +function main() -> u32 { + let mut a = 0u32; + + for i in 0..10 { + a += one(); + } + + return a +} \ No newline at end of file diff --git a/compiler/tests/function/mod.rs b/compiler/tests/function/mod.rs index 087ad808c2..19e9a5c5d7 100644 --- a/compiler/tests/function/mod.rs +++ b/compiler/tests/function/mod.rs @@ -1,7 +1,8 @@ use crate::{ + boolean::output_true, get_error, get_output, - integers::u32::output_one, + integers::u32::{output_number, output_one}, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler, @@ -109,3 +110,28 @@ fn test_multiple_returns_main() { output_multiple(program); } + +// Repeated calls + +#[test] +fn test_repeated_function_call() { + let bytes = include_bytes!("repeated.leo"); + let program = parse_program(bytes).unwrap(); + + output_true(program); +} +#[test] +fn test_iteration() { + let bytes = include_bytes!("iteration.leo"); + let program = parse_program(bytes).unwrap(); + + output_number(program, 10); +} + +#[test] +fn test_repeated_iteration() { + let bytes = include_bytes!("repeated_iteration.leo"); + let program = parse_program(bytes).unwrap(); + + output_number(program, 20u32); +} diff --git a/compiler/tests/function/repeated.leo b/compiler/tests/function/repeated.leo new file mode 100644 index 0000000000..cef685c9a8 --- /dev/null +++ b/compiler/tests/function/repeated.leo @@ -0,0 +1,7 @@ +function test() -> bool { + return true +} + +function main() -> bool { + return test() && test() +} \ No newline at end of file diff --git a/compiler/tests/function/repeated_iteration.leo b/compiler/tests/function/repeated_iteration.leo new file mode 100644 index 0000000000..d667e9fc25 --- /dev/null +++ b/compiler/tests/function/repeated_iteration.leo @@ -0,0 +1,13 @@ +function iteration() -> u32 { + let mut a = 0u32; + + for i in 0..10 { + a += 1; + } + + return a +} + +function main() -> u32 { + return iteration() + iteration() +} \ No newline at end of file diff --git a/compiler/tests/integers/macros.rs b/compiler/tests/integers/macros.rs index 4973535f7c..81eb459f98 100644 --- a/compiler/tests/integers/macros.rs +++ b/compiler/tests/integers/macros.rs @@ -44,7 +44,7 @@ macro_rules! test_uint { // None input let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![None]); - fail_synthesis(program); + fail_integer(program); } fn test_add() { diff --git a/compiler/tests/integers/mod.rs b/compiler/tests/integers/mod.rs index 4ed91e30ad..deba2d7aac 100644 --- a/compiler/tests/integers/mod.rs +++ b/compiler/tests/integers/mod.rs @@ -48,18 +48,11 @@ pub trait IntegerTester { pub(crate) fn fail_integer(program: EdwardsTestCompiler) { match get_error(program) { - CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::InvalidInteger(_string))) => {} + CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::Error(_string))) => {} error => panic!("Expected invalid boolean error, got {}", error), } } -pub(crate) fn fail_synthesis(program: EdwardsTestCompiler) { - match get_error(program) { - CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::SynthesisError(_string))) => {} - error => panic!("Expected synthesis error, got {}", error), - } -} - // must be below macro definitions! pub mod u128; pub mod u16; diff --git a/compiler/tests/integers/u128/mod.rs b/compiler/tests/integers/u128/mod.rs index 2989214a8b..236bcca519 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -2,7 +2,7 @@ use crate::{ boolean::{output_expected_boolean, output_false, output_true}, get_error, get_output, - integers::{fail_integer, fail_synthesis, IntegerTester}, + integers::{fail_integer, IntegerTester}, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler, diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index 9978bfdda8..3376355148 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -2,7 +2,7 @@ use crate::{ boolean::{output_expected_boolean, output_false, output_true}, get_error, get_output, - integers::{fail_integer, fail_synthesis, IntegerTester}, + integers::{fail_integer, IntegerTester}, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler, diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index bcc17744c1..39f9c9bbd5 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -2,7 +2,7 @@ use crate::{ boolean::{output_expected_boolean, output_false, output_true}, get_error, get_output, - integers::{fail_integer, fail_synthesis, IntegerTester}, + integers::{fail_integer, IntegerTester}, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler, diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index d1e19725ae..f07b09a1de 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -2,7 +2,7 @@ use crate::{ boolean::{output_expected_boolean, output_false, output_true}, get_error, get_output, - integers::{fail_integer, fail_synthesis, IntegerTester}, + integers::{fail_integer, IntegerTester}, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler, diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index 4e973c9c71..f0493bb211 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -2,7 +2,7 @@ use crate::{ boolean::{output_expected_boolean, output_false, output_true}, get_error, get_output, - integers::{fail_integer, fail_synthesis, IntegerTester}, + integers::{fail_integer, IntegerTester}, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler, diff --git a/compiler/tests/mod.rs b/compiler/tests/mod.rs index 3d9b665056..167328cf20 100644 --- a/compiler/tests/mod.rs +++ b/compiler/tests/mod.rs @@ -20,6 +20,7 @@ use leo_compiler::{ use snarkos_curves::edwards_bls12::Fq; use snarkos_models::gadgets::r1cs::TestConstraintSystem; +use std::path::PathBuf; pub type EdwardsTestCompiler = Compiler; pub type EdwardsConstrainedValue = ConstrainedValue; @@ -43,10 +44,18 @@ pub(crate) fn fail_enforce(program: EdwardsTestCompiler) { } } -pub(crate) fn parse_program(bytes: &[u8]) -> Result { - let program_string = String::from_utf8_lossy(bytes); +fn new_compiler() -> EdwardsTestCompiler { + let program_name = "test".to_string(); + let path = PathBuf::from("/test/src/main.leo"); + let mut compiler = EdwardsTestCompiler::new(program_name); + compiler.set_path(path); - let mut compiler = EdwardsTestCompiler::new(); + compiler +} + +pub(crate) fn parse_program(bytes: &[u8]) -> Result { + let mut compiler = new_compiler(); + let program_string = String::from_utf8_lossy(bytes); compiler.parse_program(&program_string)?; @@ -54,10 +63,9 @@ pub(crate) fn parse_program(bytes: &[u8]) -> Result Result { + let mut compiler = new_compiler(); let inputs_string = String::from_utf8_lossy(bytes); - let mut compiler = EdwardsTestCompiler::new(); - compiler.parse_inputs(&inputs_string)?; Ok(compiler) diff --git a/compiler/tests/statements/mod.rs b/compiler/tests/statements/mod.rs index 31dc76ca16..2d59beaa39 100644 --- a/compiler/tests/statements/mod.rs +++ b/compiler/tests/statements/mod.rs @@ -65,7 +65,5 @@ fn test_num_returns_fail() { let bytes = include_bytes!("num_returns_fail.leo"); let program = parse_program(bytes).unwrap(); - let error = get_error(program); - - println!("{}", error); + let _ = get_error(program); } diff --git a/compiler/tests/syntax/mod.rs b/compiler/tests/syntax/mod.rs index 994a972322..7bd068c503 100644 --- a/compiler/tests/syntax/mod.rs +++ b/compiler/tests/syntax/mod.rs @@ -28,7 +28,7 @@ fn test_undefined() { assert_eq!( format!("{}", error), vec![ - " --> 2:10", + " --> \"/test/src/main.leo\": 2:10", " |", " 2 | return a", " | ^", diff --git a/examples/fibonacci/inputs/fibonacci.in b/examples/fibonacci/inputs/fibonacci.in new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/fibonacci/src/main.leo b/examples/fibonacci/src/main.leo index b1cd8efb3a..a759e3d010 100644 --- a/examples/fibonacci/src/main.leo +++ b/examples/fibonacci/src/main.leo @@ -1,27 +1,16 @@ -function fibonacci(i: u32) -> u32 { - if i == 0 { - return 0 - } else if i == 1 { - return 1 - } else { - return fibonacci(i - 1) + fibonacci(i - 2) +function fibonacci() -> u32 { + let mut a = 0u32; + let mut b = 1u32; + + for i in 0..10 { + a = b; + b = a + b; } + + return a } // The 'fibonacci' main function. function main() -> u32 { - return fibonacci(1) -} - - -Function mutateNoLet(b: bool) { - let mut a = 5; - if b { - // must be turned into statements.conditional expression - a = 0; - // a = if b ? 0 : a; - } else { - a = 3; - // a = if b ? a : 3; - } + return fibonacci() } \ No newline at end of file diff --git a/examples/hello_world/inputs/hello_world.in b/examples/hello_world/inputs/hello_world.in new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/hello_world/src/main.leo b/examples/hello_world/src/main.leo index 8ba761a003..b51882a62f 100644 --- a/examples/hello_world/src/main.leo +++ b/examples/hello_world/src/main.leo @@ -1,5 +1,5 @@ // The 'hello_world' main function. function main() -> u32 { - let a = 1 + 1; + let a: u32 = 1 + 1; return a } diff --git a/examples/square_root/.gitignore b/examples/square_root/.gitignore new file mode 100644 index 0000000000..17aa483ab4 --- /dev/null +++ b/examples/square_root/.gitignore @@ -0,0 +1 @@ +outputs/ diff --git a/examples/square_root/Leo.toml b/examples/square_root/Leo.toml new file mode 100644 index 0000000000..28a89b9c2c --- /dev/null +++ b/examples/square_root/Leo.toml @@ -0,0 +1,3 @@ +[package] +name = "square_root" +version = "0.1.0" diff --git a/examples/square_root/inputs/square_root.in b/examples/square_root/inputs/square_root.in new file mode 100644 index 0000000000..2e242a3427 --- /dev/null +++ b/examples/square_root/inputs/square_root.in @@ -0,0 +1,4 @@ +// The program inputs for square_root/src/main.leo +[main] +a: field = 337; +b: field = 113569; \ No newline at end of file diff --git a/examples/square_root/src/main.leo b/examples/square_root/src/main.leo new file mode 100644 index 0000000000..7b63b27007 --- /dev/null +++ b/examples/square_root/src/main.leo @@ -0,0 +1,5 @@ +// The 'square_root' main function. +// prove knowledge of the square root `a` of a number `b`: +function main(a: field, b: field) -> bool { + return a * a == b +} diff --git a/leo-inputs/src/lib.rs b/leo-inputs/src/lib.rs index d8e5ef8e90..80ae76ed80 100644 --- a/leo-inputs/src/lib.rs +++ b/leo-inputs/src/lib.rs @@ -34,7 +34,6 @@ impl LeoInputsParser { // Build the abstract syntax tree let syntax_tree = files::File::from_pest(&mut file).map_err(|_| InputParserError::SyntaxTreeError)?; - // println!("{:?}", syntax_tree); Ok(syntax_tree) } diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index 0beff09f8d..a1e4cb1957 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -3,67 +3,180 @@ use crate::errors::*; #[derive(Debug, Error)] pub enum CLIError { #[error("{}", _0)] - BuildError(#[from] BuildError), + BuildError(BuildError), #[error("{}: {}", _0, _1)] Crate(&'static str, String), #[error("{}", _0)] - ChecksumFileError(#[from] ChecksumFileError), + ChecksumFileError(ChecksumFileError), #[error("{}", _0)] - GitignoreError(#[from] GitignoreError), + GitignoreError(GitignoreError), #[error("{}", _0)] - InitError(#[from] InitError), + InitError(InitError), #[error("{}", _0)] - InputsDirectoryError(#[from] InputsDirectoryError), + InputsDirectoryError(InputsDirectoryError), #[error("{}", _0)] - InputsFileError(#[from] InputsFileError), + InputsFileError(InputsFileError), #[error("{}", _0)] - MainFileError(#[from] MainFileError), + MainFileError(MainFileError), #[error("{}", _0)] - ManifestError(#[from] ManifestError), + ManifestError(ManifestError), #[error("{}", _0)] - NewError(#[from] NewError), + NewError(NewError), #[error("{}", _0)] - OutputsDirectoryError(#[from] OutputsDirectoryError), + OutputsDirectoryError(OutputsDirectoryError), #[error("{}", _0)] - ProofFileError(#[from] ProofFileError), + ProofFileError(ProofFileError), #[error("{}", _0)] - ProvingKeyFileError(#[from] ProvingKeyFileError), + ProvingKeyFileError(ProvingKeyFileError), #[error("{}", _0)] - RunError(#[from] RunError), + RunError(RunError), #[error("{}", _0)] - SourceDirectoryError(#[from] SourceDirectoryError), + SourceDirectoryError(SourceDirectoryError), #[error("{}", _0)] - TestError(#[from] TestError), + TestError(TestError), #[error("{}", _0)] - VerificationKeyFileError(#[from] VerificationKeyFileError), + VerificationKeyFileError(VerificationKeyFileError), +} + +impl From for CLIError { + fn from(error: BuildError) -> Self { + log::error!("{}\n", error); + CLIError::BuildError(error) + } +} + +impl From for CLIError { + fn from(error: ChecksumFileError) -> Self { + log::error!("{}\n", error); + CLIError::ChecksumFileError(error) + } +} + +impl From for CLIError { + fn from(error: GitignoreError) -> Self { + log::error!("{}\n", error); + CLIError::GitignoreError(error) + } +} + +impl From for CLIError { + fn from(error: InitError) -> Self { + log::error!("{}\n", error); + CLIError::InitError(error) + } +} + +impl From for CLIError { + fn from(error: InputsDirectoryError) -> Self { + log::error!("{}\n", error); + CLIError::InputsDirectoryError(error) + } +} + +impl From for CLIError { + fn from(error: InputsFileError) -> Self { + log::error!("{}\n", error); + CLIError::InputsFileError(error) + } +} + +impl From for CLIError { + fn from(error: MainFileError) -> Self { + log::error!("{}\n", error); + CLIError::MainFileError(error) + } +} + +impl From for CLIError { + fn from(error: ManifestError) -> Self { + log::error!("{}\n", error); + CLIError::ManifestError(error) + } +} + +impl From for CLIError { + fn from(error: NewError) -> Self { + log::error!("{}\n", error); + CLIError::NewError(error) + } +} + +impl From for CLIError { + fn from(error: OutputsDirectoryError) -> Self { + log::error!("{}\n", error); + CLIError::OutputsDirectoryError(error) + } +} + +impl From for CLIError { + fn from(error: ProofFileError) -> Self { + log::error!("{}\n", error); + CLIError::ProofFileError(error) + } +} + +impl From for CLIError { + fn from(error: ProvingKeyFileError) -> Self { + log::error!("{}\n", error); + CLIError::ProvingKeyFileError(error) + } +} + +impl From for CLIError { + fn from(error: RunError) -> Self { + log::error!("{}\n", error); + CLIError::RunError(error) + } +} + +impl From for CLIError { + fn from(error: SourceDirectoryError) -> Self { + log::error!("{}\n", error); + CLIError::SourceDirectoryError(error) + } +} + +impl From for CLIError { + fn from(error: TestError) -> Self { + log::error!("{}\n", error); + CLIError::TestError(error) + } +} + +impl From for CLIError { + fn from(error: VerificationKeyFileError) -> Self { + log::error!("{}\n", error); + CLIError::VerificationKeyFileError(error) + } } impl From for CLIError { fn from(error: leo_compiler::errors::CompilerError) -> Self { - log::error!("{}", error); + log::error!("{}\n", error); CLIError::Crate("leo_compiler", "Program failed due to previous error".into()) } } impl From for CLIError { fn from(error: leo_inputs::errors::InputParserError) -> Self { - CLIError::Crate("leo_inputs", format!("{}", error)) + log::error!("{}\n", error); + CLIError::Crate("leo_inputs", "Program failed due to previous error".into()) } } diff --git a/types/src/common/range_or_expression.rs b/types/src/common/range_or_expression.rs index 2e57e0ddde..a006f28c26 100644 --- a/types/src/common/range_or_expression.rs +++ b/types/src/common/range_or_expression.rs @@ -16,12 +16,12 @@ impl<'ast> From> for RangeOrExpression { AstRangeOrExpression::Range(range) => { let from = range.from.map(|from| match Expression::from(from.0) { Expression::Integer(number) => number, - Expression::Implicit(string) => Integer::from_implicit(string), + Expression::Implicit(string, _span) => Integer::from_implicit(string), expression => unimplemented!("Range bounds should be integers, found {}", expression), }); let to = range.to.map(|to| match Expression::from(to.0) { Expression::Integer(number) => number, - Expression::Implicit(string) => Integer::from_implicit(string), + Expression::Implicit(string, _span) => Integer::from_implicit(string), expression => unimplemented!("Range bounds should be integers, found {}", expression), }); diff --git a/types/src/common/span.rs b/types/src/common/span.rs index fc3f96be5d..b9a0adc144 100644 --- a/types/src/common/span.rs +++ b/types/src/common/span.rs @@ -15,12 +15,16 @@ pub struct Span { impl<'ast> From> for Span { fn from(span: AstSpan<'ast>) -> Self { let mut text = " ".to_string(); + let line_col = span.start_pos().line_col(); + let end = span.end_pos().line_col().1; + text.push_str(span.start_pos().line_of().trim_end()); + Self { text, - line: span.start_pos().line_col().0, - start: find_line_start(&span.start_pos()), - end: find_line_end(&span.end_pos()), + line: line_col.0, + start: line_col.1, + end, } } } diff --git a/compiler/src/errors/error.rs b/types/src/errors/error.rs similarity index 90% rename from compiler/src/errors/error.rs rename to types/src/errors/error.rs index 60cc40ff64..4d2a7fdefa 100644 --- a/compiler/src/errors/error.rs +++ b/types/src/errors/error.rs @@ -1,6 +1,8 @@ -use leo_types::Span; +use crate::Span; -use std::fmt; +use std::{fmt, path::PathBuf}; + +pub const INDENT: &'static str = " "; /// Formatted compiler error type /// --> file.leo 2:8 @@ -37,8 +39,11 @@ impl Error { } } + pub fn set_path(&mut self, path: PathBuf) { + self.path = Some(format!("{:?}", path)); + } + pub fn format(&self) -> String { - let indent = " ".to_string(); let path = self.path.as_ref().map(|path| format!("{}:", path)).unwrap_or_default(); let underline = underline(self.start, self.end); @@ -49,8 +54,8 @@ impl Error { {indent } | {underline}\n\ {indent } |\n\ {indent } = {message}", - indent = indent, - width = indent.len(), + indent = INDENT, + width = INDENT.len(), path = path, line = self.line, start = self.start, diff --git a/types/src/errors/integer.rs b/types/src/errors/integer.rs index 5d71113a49..a8777536d3 100644 --- a/types/src/errors/integer.rs +++ b/types/src/errors/integer.rs @@ -1,18 +1,59 @@ -use snarkos_errors::gadgets::SynthesisError; +use crate::{error::Error as FormattedError, Span}; -use std::num::ParseIntError; +use snarkos_errors::gadgets::SynthesisError; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum IntegerError { - #[error("Cannot enforce {}", _0)] - CannotEnforce(String), - - #[error("Expected integer parameter, got {}", _0)] - InvalidInteger(String), - #[error("{}", _0)] - ParseIntError(#[from] ParseIntError), - - #[error("{}", _0)] - SynthesisError(#[from] SynthesisError), + Error(#[from] FormattedError), +} + +impl IntegerError { + pub fn set_path(&mut self, path: PathBuf) { + match self { + IntegerError::Error(error) => error.set_path(path), + } + } + + fn new_from_span(message: String, span: Span) -> Self { + IntegerError::Error(FormattedError::new_from_span(message, span)) + } + + pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self { + let message = format!( + "the integer operation `{}` failed due to the synthesis error `{}`", + operation, error, + ); + + Self::new_from_span(message, span) + } + + pub fn cannot_evaluate(operation: String, span: Span) -> Self { + let message = format!( + "the integer binary operation `{}` can only be enforced on integers of the same type", + operation + ); + + Self::new_from_span(message, span) + } + + pub fn invalid_index(span: Span) -> Self { + let message = + format!("index must be a constant value integer. allocated indices produce a circuit of unknown size"); + + Self::new_from_span(message, span) + } + + pub fn invalid_integer(actual: String, span: Span) -> Self { + let message = format!("expected integer input type, found `{}`", actual); + + Self::new_from_span(message, span) + } + + pub fn missing_integer(expected: String, span: Span) -> Self { + let message = format!("expected integer input `{}` not found", expected); + + Self::new_from_span(message, span) + } } diff --git a/types/src/errors/mod.rs b/types/src/errors/mod.rs index b817aa2387..c25bdf0b54 100644 --- a/types/src/errors/mod.rs +++ b/types/src/errors/mod.rs @@ -1,2 +1,5 @@ +pub mod error; +pub use error::*; + pub mod integer; pub use integer::*; diff --git a/types/src/expression.rs b/types/src/expression.rs index 518a8d2d7f..bc5c6b1ba4 100644 --- a/types/src/expression.rs +++ b/types/src/expression.rs @@ -28,10 +28,10 @@ pub enum Expression { // Values Integer(Integer), - Field(String), - Group(String), + Field(String, Span), + Group(String, Span), Boolean(Boolean), - Implicit(String), + Implicit(String, Span), // Number operations Add(Box, Box, Span), @@ -41,7 +41,7 @@ pub enum Expression { Pow(Box, Box, Span), // Boolean operations - Not(Box), + Not(Box, Span), Or(Box, Box, Span), And(Box, Box, Span), Eq(Box, Box, Span), @@ -66,6 +66,41 @@ pub enum Expression { FunctionCall(Box, Vec, Span), } +impl Expression { + pub fn set_span(&mut self, new_span: &Span) { + match self { + Expression::Field(_, old_span) => *old_span = new_span.clone(), + Expression::Group(_, old_span) => *old_span = new_span.clone(), + + Expression::Add(_, _, old_span) => *old_span = new_span.clone(), + Expression::Sub(_, _, old_span) => *old_span = new_span.clone(), + Expression::Mul(_, _, old_span) => *old_span = new_span.clone(), + Expression::Div(_, _, old_span) => *old_span = new_span.clone(), + Expression::Pow(_, _, old_span) => *old_span = new_span.clone(), + + Expression::Not(_, old_span) => *old_span = new_span.clone(), + Expression::Or(_, _, old_span) => *old_span = new_span.clone(), + Expression::And(_, _, old_span) => *old_span = new_span.clone(), + Expression::Eq(_, _, old_span) => *old_span = new_span.clone(), + Expression::Ge(_, _, old_span) => *old_span = new_span.clone(), + Expression::Gt(_, _, old_span) => *old_span = new_span.clone(), + Expression::Le(_, _, old_span) => *old_span = new_span.clone(), + Expression::Lt(_, _, old_span) => *old_span = new_span.clone(), + + Expression::IfElse(_, _, _, old_span) => *old_span = new_span.clone(), + Expression::Array(_, old_span) => *old_span = new_span.clone(), + Expression::ArrayAccess(_, _, old_span) => *old_span = new_span.clone(), + + Expression::Circuit(_, _, old_span) => *old_span = new_span.clone(), + Expression::CircuitMemberAccess(_, _, old_span) => *old_span = new_span.clone(), + Expression::CircuitStaticFunctionAccess(_, _, old_span) => *old_span = new_span.clone(), + + Expression::FunctionCall(_, _, old_span) => *old_span = new_span.clone(), + _ => {} + } + } +} + impl<'ast> Expression { pub(crate) fn get_count(count: Value<'ast>) -> usize { match count { @@ -88,10 +123,10 @@ impl<'ast> fmt::Display for Expression { // Values Expression::Integer(ref integer) => write!(f, "{}", integer), - Expression::Field(ref field) => write!(f, "{}", field), - Expression::Group(ref group) => write!(f, "{}", group), + Expression::Field(ref field, ref _span) => write!(f, "{}", field), + Expression::Group(ref group, ref _span) => write!(f, "{}", group), Expression::Boolean(ref bool) => write!(f, "{}", bool.get_value().unwrap()), - Expression::Implicit(ref value) => write!(f, "{}", value), + Expression::Implicit(ref value, ref _span) => write!(f, "{}", value), // Number operations Expression::Add(ref left, ref right, ref _span) => write!(f, "{} + {}", left, right), @@ -101,7 +136,7 @@ impl<'ast> fmt::Display for Expression { Expression::Pow(ref left, ref right, ref _span) => write!(f, "{} ** {}", left, right), // Boolean operations - Expression::Not(ref expression) => write!(f, "!{}", expression), + Expression::Not(ref expression, ref _span) => write!(f, "!{}", expression), Expression::Or(ref lhs, ref rhs, ref _span) => write!(f, "{} || {}", lhs, rhs), Expression::And(ref lhs, ref rhs, ref _span) => write!(f, "{} && {}", lhs, rhs), Expression::Eq(ref lhs, ref rhs, ref _span) => write!(f, "{} == {}", lhs, rhs), @@ -194,15 +229,18 @@ impl<'ast> From> for Expression { ), // Handle function calls - Access::Call(function) => Expression::FunctionCall( - Box::new(acc), - function - .expressions - .into_iter() - .map(|expression| Expression::from(expression)) - .collect(), - Span::from(function.span), - ), + Access::Call(function) => { + let span = Span::from(function.span); + Expression::FunctionCall( + Box::new(acc), + function + .expressions + .into_iter() + .map(|expression| Expression::from(expression)) + .collect(), + span, + ) + } // Handle circuit member accesses Access::Object(circuit_object) => Expression::CircuitMemberAccess( @@ -278,7 +316,10 @@ impl<'ast> From> for Expression { Box::new(Expression::from(*expression.right)), Span::from(expression.span), ), - BinaryOperation::Ne => Expression::Not(Box::new(Expression::from(expression))), + BinaryOperation::Ne => Expression::Not( + Box::new(Expression::from(expression.clone())), + Span::from(expression.span), + ), BinaryOperation::Ge => Expression::Ge( Box::new(Expression::from(*expression.left)), Box::new(Expression::from(*expression.right)), @@ -376,19 +417,22 @@ impl<'ast> From> for Expression { impl<'ast> From> for Expression { fn from(expression: NotExpression<'ast>) -> Self { - Expression::Not(Box::new(Expression::from(*expression.expression))) + Expression::Not( + Box::new(Expression::from(*expression.expression)), + Span::from(expression.span), + ) } } impl<'ast> From> for Expression { fn from(field: FieldValue<'ast>) -> Self { - Expression::Field(field.number.value) + Expression::Field(field.number.value, Span::from(field.span)) } } impl<'ast> From> for Expression { fn from(group: GroupValue<'ast>) -> Self { - Expression::Group(group.to_string()) + Expression::Group(group.to_string(), Span::from(group.span)) } } @@ -402,7 +446,7 @@ impl<'ast> From> for Expression { impl<'ast> From> for Expression { fn from(number: NumberImplicitValue<'ast>) -> Self { - Expression::Implicit(number.number.value) + Expression::Implicit(number.number.value, Span::from(number.span)) } } diff --git a/types/src/functions/function_input.rs b/types/src/functions/function_input.rs index 0f522b4cad..e28b12a8e2 100644 --- a/types/src/functions/function_input.rs +++ b/types/src/functions/function_input.rs @@ -1,4 +1,4 @@ -use crate::{Identifier, Type}; +use crate::{Identifier, Span, Type}; use leo_ast::functions::FunctionInput as AstFunctionInput; use std::fmt; @@ -8,6 +8,7 @@ pub struct FunctionInput { pub identifier: Identifier, pub mutable: bool, pub _type: Type, + pub span: Span, } impl<'ast> From> for FunctionInput { @@ -16,6 +17,7 @@ impl<'ast> From> for FunctionInput { identifier: Identifier::from(parameter.identifier), mutable: parameter.mutable.is_some(), _type: Type::from(parameter._type), + span: Span::from(parameter.span), } } } diff --git a/types/src/imports/import.rs b/types/src/imports/import.rs index 1caa243fcf..5f0a1947cc 100644 --- a/types/src/imports/import.rs +++ b/types/src/imports/import.rs @@ -1,6 +1,6 @@ //! The import type for a Leo program. -use crate::ImportSymbol; +use crate::{ImportSymbol, Span}; use leo_ast::imports::Import as AstImport; use std::fmt; @@ -9,6 +9,7 @@ use std::fmt; pub struct Import { pub path_string: String, pub symbols: Vec, + pub span: Span, } impl<'ast> From> for Import { @@ -20,18 +21,12 @@ impl<'ast> From> for Import { .into_iter() .map(|symbol| ImportSymbol::from(symbol)) .collect(), + span: Span::from(import.span), } } } impl Import { - pub fn new(source: String, symbols: Vec) -> Import { - Import { - path_string: source, - symbols, - } - } - pub fn path_string_full(&self) -> String { format!("{}.leo", self.path_string) } diff --git a/types/src/imports/import_symbol.rs b/types/src/imports/import_symbol.rs index 17e6257296..1c96198764 100644 --- a/types/src/imports/import_symbol.rs +++ b/types/src/imports/import_symbol.rs @@ -1,4 +1,4 @@ -use crate::Identifier; +use crate::{Identifier, Span}; use leo_ast::imports::ImportSymbol as AstImportSymbol; use std::fmt; @@ -7,6 +7,7 @@ use std::fmt; pub struct ImportSymbol { pub symbol: Identifier, pub alias: Option, + pub span: Span, } impl<'ast> From> for ImportSymbol { @@ -14,6 +15,7 @@ impl<'ast> From> for ImportSymbol { ImportSymbol { symbol: Identifier::from(symbol.value), alias: symbol.alias.map(|alias| Identifier::from(alias)), + span: Span::from(symbol.span), } } } diff --git a/types/src/integer.rs b/types/src/integer.rs index 4eece3ebb1..e83c5b8eab 100644 --- a/types/src/integer.rs +++ b/types/src/integer.rs @@ -1,6 +1,6 @@ //! Conversion of integer declarations to constraints in Leo. -use crate::{errors::IntegerError, InputValue, IntegerType}; +use crate::{errors::IntegerError, InputValue, IntegerType, Span}; use leo_ast::{types::IntegerType as AstIntegerType, values::NumberValue}; use snarkos_errors::gadgets::SynthesisError; @@ -58,6 +58,46 @@ impl<'ast> Integer { } impl Integer { + pub fn new_constant(integer_type: &IntegerType, string: String, span: Span) -> Result { + match integer_type { + IntegerType::U8 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U8(UInt8::constant(number))) + } + IntegerType::U16 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U16(UInt16::constant(number))) + } + IntegerType::U32 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U32(UInt32::constant(number))) + } + IntegerType::U64 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U64(UInt64::constant(number))) + } + IntegerType::U128 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U128(UInt128::constant(number))) + } + } + } + pub fn get_value(&self) -> Option { match self { Integer::U8(u8) => u8.value.map(|v| v as u128), @@ -68,8 +108,9 @@ impl Integer { } } - pub fn to_usize(&self) -> usize { - self.get_value().unwrap() as usize + pub fn to_usize(&self, span: Span) -> Result { + let value = self.get_value().ok_or(IntegerError::invalid_index(span))?; + Ok(value as usize) } pub fn get_type(&self) -> IntegerType { @@ -87,36 +128,61 @@ impl Integer { integer_type: IntegerType, name: String, option: Option, + span: Span, ) -> Result { Ok(match integer_type { IntegerType::U8 => { + let u8_name = format!("{}: u8", name); + let u8_name_unique = format!("`{}` {}:{}", u8_name, span.line, span.start); let u8_option = option.map(|integer| integer as u8); - let u8_result = UInt8::alloc(cs.ns(|| name), || u8_option.ok_or(SynthesisError::AssignmentMissing))?; + let u8_result = UInt8::alloc(cs.ns(|| u8_name_unique), || { + u8_option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| IntegerError::missing_integer(u8_name, span))?; Integer::U8(u8_result) } IntegerType::U16 => { + let u16_name = format!("{}: u16", name); + let u16_name_unique = format!("`{}` {}:{}", u16_name, span.line, span.start); let u16_option = option.map(|integer| integer as u16); - let u16_result = UInt16::alloc(cs.ns(|| name), || u16_option.ok_or(SynthesisError::AssignmentMissing))?; + let u16_result = UInt16::alloc(cs.ns(|| u16_name_unique), || { + u16_option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| IntegerError::missing_integer(u16_name, span))?; Integer::U16(u16_result) } IntegerType::U32 => { + let u32_name = format!("{}: u32", name); + let u32_name_unique = format!("`{}` {}:{}", u32_name, span.line, span.start); let u32_option = option.map(|integer| integer as u32); - let u32_result = UInt32::alloc(cs.ns(|| name), || u32_option.ok_or(SynthesisError::AssignmentMissing))?; + let u32_result = UInt32::alloc(cs.ns(|| u32_name_unique), || { + u32_option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| IntegerError::missing_integer(u32_name, span))?; Integer::U32(u32_result) } IntegerType::U64 => { + let u64_name = format!("{}: u64", name); + let u64_name_unique = format!("`{}` {}:{}", u64_name, span.line, span.start); let u64_option = option.map(|integer| integer as u64); - let u64_result = UInt64::alloc(cs.ns(|| name), || u64_option.ok_or(SynthesisError::AssignmentMissing))?; + let u64_result = UInt64::alloc(cs.ns(|| u64_name_unique), || { + u64_option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| IntegerError::missing_integer(u64_name, span))?; Integer::U64(u64_result) } IntegerType::U128 => { + let u128_name = format!("{}: u128", name); + let u128_name_unique = format!("`{}` {}:{}", u128_name, span.line, span.start); let u128_option = option.map(|integer| integer as u128); - let u128_result = - UInt128::alloc(cs.ns(|| name), || u128_option.ok_or(SynthesisError::AssignmentMissing))?; + let u128_result = UInt128::alloc(cs.ns(|| u128_name_unique), || { + u128_option.ok_or(SynthesisError::AssignmentMissing) + }) + .map_err(|_| IntegerError::missing_integer(u128_name, span))?; Integer::U128(u128_result) } @@ -128,6 +194,7 @@ impl Integer { integer_type: IntegerType, name: String, integer_value: Option, + span: Span, ) -> Result { // Check that the input value is the correct type let option = match integer_value { @@ -135,57 +202,55 @@ impl Integer { if let InputValue::Integer(_type_, number) = input { Some(number) } else { - return Err(IntegerError::InvalidInteger(input.to_string())); + return Err(IntegerError::invalid_integer(input.to_string(), span)); } } None => None, }; - Self::allocate_type(cs, integer_type, name, option) + Self::allocate_type(cs, integer_type, name, option, span) } pub fn add>( self, cs: &mut CS, other: Self, + span: Span, ) -> Result { + let unique_namespace = format!("enforce {} + {} {}:{}", self, other, span.line, span.start); + Ok(match (self, other) { (Integer::U8(left_u8), Integer::U8(right_u8)) => { - let result = UInt8::addmany( - cs.ns(|| format!("enforce {} + {}", left_u8.value.unwrap(), right_u8.value.unwrap())), - &[left_u8, right_u8], - )?; + let result = UInt8::addmany(cs.ns(|| unique_namespace), &[left_u8, right_u8]) + .map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?; + Integer::U8(result) } (Integer::U16(left_u16), Integer::U16(right_u16)) => { - let result = UInt16::addmany( - cs.ns(|| format!("enforce {} + {}", left_u16.value.unwrap(), right_u16.value.unwrap())), - &[left_u16, right_u16], - )?; + let result = UInt16::addmany(cs.ns(|| unique_namespace), &[left_u16, right_u16]) + .map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?; + Integer::U16(result) } (Integer::U32(left_u32), Integer::U32(right_u32)) => { - let result = UInt32::addmany( - cs.ns(|| format!("enforce {} + {}", left_u32.value.unwrap(), right_u32.value.unwrap())), - &[left_u32, right_u32], - )?; + let result = UInt32::addmany(cs.ns(|| unique_namespace), &[left_u32, right_u32]) + .map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?; + Integer::U32(result) } (Integer::U64(left_u64), Integer::U64(right_u64)) => { - let result = UInt64::addmany( - cs.ns(|| format!("enforce {} + {}", left_u64.value.unwrap(), right_u64.value.unwrap())), - &[left_u64, right_u64], - )?; + let result = UInt64::addmany(cs.ns(|| unique_namespace), &[left_u64, right_u64]) + .map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?; + Integer::U64(result) } (Integer::U128(left_u128), Integer::U128(right_u128)) => { - let result = UInt128::addmany( - cs.ns(|| format!("enforce {} + {}", left_u128.value.unwrap(), right_u128.value.unwrap())), - &[left_u128, right_u128], - )?; + let result = UInt128::addmany(cs.ns(|| unique_namespace), &[left_u128, right_u128]) + .map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?; + Integer::U128(result) } - (left, right) => return Err(IntegerError::CannotEnforce(format!("{} + {}", left, right))), + (_, _) => return Err(IntegerError::cannot_evaluate(format!("+"), span)), }) } @@ -193,44 +258,47 @@ impl Integer { self, cs: &mut CS, other: Self, + span: Span, ) -> Result { + let unique_namespace = format!("enforce {} - {} {}:{}", self, other, span.line, span.start); + Ok(match (self, other) { (Integer::U8(left_u8), Integer::U8(right_u8)) => { - let result = left_u8.sub( - cs.ns(|| format!("enforce {} - {}", left_u8.value.unwrap(), right_u8.value.unwrap())), - &right_u8, - )?; + let result = left_u8 + .sub(cs.ns(|| unique_namespace), &right_u8) + .map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?; + Integer::U8(result) } (Integer::U16(left_u16), Integer::U16(right_u16)) => { - let result = left_u16.sub( - cs.ns(|| format!("enforce {} - {}", left_u16.value.unwrap(), right_u16.value.unwrap())), - &right_u16, - )?; + let result = left_u16 + .sub(cs.ns(|| unique_namespace), &right_u16) + .map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?; + Integer::U16(result) } (Integer::U32(left_u32), Integer::U32(right_u32)) => { - let result = left_u32.sub( - cs.ns(|| format!("enforce {} - {}", left_u32.value.unwrap(), right_u32.value.unwrap())), - &right_u32, - )?; + let result = left_u32 + .sub(cs.ns(|| unique_namespace), &right_u32) + .map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?; + Integer::U32(result) } (Integer::U64(left_u64), Integer::U64(right_u64)) => { - let result = left_u64.sub( - cs.ns(|| format!("enforce {} - {}", left_u64.value.unwrap(), right_u64.value.unwrap())), - &right_u64, - )?; + let result = left_u64 + .sub(cs.ns(|| unique_namespace), &right_u64) + .map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?; + Integer::U64(result) } (Integer::U128(left_u128), Integer::U128(right_u128)) => { - let result = left_u128.sub( - cs.ns(|| format!("enforce {} - {}", left_u128.value.unwrap(), right_u128.value.unwrap())), - &right_u128, - )?; + let result = left_u128 + .sub(cs.ns(|| unique_namespace), &right_u128) + .map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?; + Integer::U128(result) } - (left, right) => return Err(IntegerError::CannotEnforce(format!("{} - {}", left, right))), + (_, _) => return Err(IntegerError::cannot_evaluate(format!("-"), span)), }) } @@ -238,44 +306,47 @@ impl Integer { self, cs: &mut CS, other: Self, + span: Span, ) -> Result { + let unique_namespace = format!("enforce {} * {} {}:{}", self, other, span.line, span.start); + Ok(match (self, other) { (Integer::U8(left_u8), Integer::U8(right_u8)) => { - let result = left_u8.mul( - cs.ns(|| format!("enforce {} * {}", left_u8.value.unwrap(), right_u8.value.unwrap())), - &right_u8, - )?; + let result = left_u8 + .mul(cs.ns(|| unique_namespace), &right_u8) + .map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?; + Integer::U8(result) } (Integer::U16(left_u16), Integer::U16(right_u16)) => { - let result = left_u16.mul( - cs.ns(|| format!("enforce {} * {}", left_u16.value.unwrap(), right_u16.value.unwrap())), - &right_u16, - )?; + let result = left_u16 + .mul(cs.ns(|| unique_namespace), &right_u16) + .map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?; + Integer::U16(result) } (Integer::U32(left_u32), Integer::U32(right_u32)) => { - let result = left_u32.mul( - cs.ns(|| format!("enforce {} * {}", left_u32.value.unwrap(), right_u32.value.unwrap())), - &right_u32, - )?; + let result = left_u32 + .mul(cs.ns(|| unique_namespace), &right_u32) + .map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?; + Integer::U32(result) } (Integer::U64(left_u64), Integer::U64(right_u64)) => { - let result = left_u64.mul( - cs.ns(|| format!("enforce {} * {}", left_u64.value.unwrap(), right_u64.value.unwrap())), - &right_u64, - )?; + let result = left_u64 + .mul(cs.ns(|| unique_namespace), &right_u64) + .map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?; + Integer::U64(result) } (Integer::U128(left_u128), Integer::U128(right_u128)) => { - let result = left_u128.mul( - cs.ns(|| format!("enforce {} * {}", left_u128.value.unwrap(), right_u128.value.unwrap())), - &right_u128, - )?; + let result = left_u128 + .mul(cs.ns(|| unique_namespace), &right_u128) + .map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?; + Integer::U128(result) } - (left, right) => return Err(IntegerError::CannotEnforce(format!("{} * {}", left, right))), + (_, _) => return Err(IntegerError::cannot_evaluate(format!("*"), span)), }) } @@ -283,44 +354,47 @@ impl Integer { self, cs: &mut CS, other: Self, + span: Span, ) -> Result { + let unique_namespace = format!("enforce {} ÷ {} {}:{}", self, other, span.line, span.start); + Ok(match (self, other) { (Integer::U8(left_u8), Integer::U8(right_u8)) => { - let result = left_u8.div( - cs.ns(|| format!("enforce {} ÷ {}", left_u8.value.unwrap(), right_u8.value.unwrap())), - &right_u8, - )?; + let result = left_u8 + .div(cs.ns(|| unique_namespace), &right_u8) + .map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?; + Integer::U8(result) } (Integer::U16(left_u16), Integer::U16(right_u16)) => { - let result = left_u16.div( - cs.ns(|| format!("enforce {} ÷ {}", left_u16.value.unwrap(), right_u16.value.unwrap())), - &right_u16, - )?; + let result = left_u16 + .div(cs.ns(|| unique_namespace), &right_u16) + .map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?; + Integer::U16(result) } (Integer::U32(left_u32), Integer::U32(right_u32)) => { - let result = left_u32.div( - cs.ns(|| format!("enforce {} ÷ {}", left_u32.value.unwrap(), right_u32.value.unwrap())), - &right_u32, - )?; + let result = left_u32 + .div(cs.ns(|| unique_namespace), &right_u32) + .map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?; + Integer::U32(result) } (Integer::U64(left_u64), Integer::U64(right_u64)) => { - let result = left_u64.div( - cs.ns(|| format!("enforce {} ÷ {}", left_u64.value.unwrap(), right_u64.value.unwrap())), - &right_u64, - )?; + let result = left_u64 + .div(cs.ns(|| unique_namespace), &right_u64) + .map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?; + Integer::U64(result) } (Integer::U128(left_u128), Integer::U128(right_u128)) => { - let result = left_u128.div( - cs.ns(|| format!("enforce {} ÷ {}", left_u128.value.unwrap(), right_u128.value.unwrap())), - &right_u128, - )?; + let result = left_u128 + .div(cs.ns(|| unique_namespace), &right_u128) + .map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?; + Integer::U128(result) } - (left, right) => return Err(IntegerError::CannotEnforce(format!("{} ÷ {}", left, right))), + (_, _) => return Err(IntegerError::cannot_evaluate(format!("÷"), span)), }) } @@ -328,44 +402,47 @@ impl Integer { self, cs: &mut CS, other: Self, + span: Span, ) -> Result { + let unique_namespace = format!("enforce {} ** {} {}:{}", self, other, span.line, span.start); + Ok(match (self, other) { (Integer::U8(left_u8), Integer::U8(right_u8)) => { - let result = left_u8.pow( - cs.ns(|| format!("enforce {} ** {}", left_u8.value.unwrap(), right_u8.value.unwrap())), - &right_u8, - )?; + let result = left_u8 + .pow(cs.ns(|| unique_namespace), &right_u8) + .map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?; + Integer::U8(result) } (Integer::U16(left_u16), Integer::U16(right_u16)) => { - let result = left_u16.pow( - cs.ns(|| format!("enforce {} ** {}", left_u16.value.unwrap(), right_u16.value.unwrap())), - &right_u16, - )?; + let result = left_u16 + .pow(cs.ns(|| unique_namespace), &right_u16) + .map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?; + Integer::U16(result) } (Integer::U32(left_u32), Integer::U32(right_u32)) => { - let result = left_u32.pow( - cs.ns(|| format!("enforce {} ** {}", left_u32.value.unwrap(), right_u32.value.unwrap())), - &right_u32, - )?; + let result = left_u32 + .pow(cs.ns(|| unique_namespace), &right_u32) + .map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?; + Integer::U32(result) } (Integer::U64(left_u64), Integer::U64(right_u64)) => { - let result = left_u64.pow( - cs.ns(|| format!("enforce {} ** {}", left_u64.value.unwrap(), right_u64.value.unwrap())), - &right_u64, - )?; + let result = left_u64 + .pow(cs.ns(|| unique_namespace), &right_u64) + .map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?; + Integer::U64(result) } (Integer::U128(left_u128), Integer::U128(right_u128)) => { - let result = left_u128.pow( - cs.ns(|| format!("enforce {} ** {}", left_u128.value.unwrap(), right_u128.value.unwrap())), - &right_u128, - )?; + let result = left_u128 + .pow(cs.ns(|| unique_namespace), &right_u128) + .map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?; + Integer::U128(result) } - (left, right) => return Err(IntegerError::CannotEnforce(format!("{} ** {}", left, right))), + (_, _) => return Err(IntegerError::cannot_evaluate(format!("**"), span)), }) } } @@ -450,11 +527,11 @@ impl CondSelectGadget for Integer { impl fmt::Display for Integer { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let option = match self { - Integer::U8(u8) => u8.value.map(|num| num as usize), - Integer::U16(u16) => u16.value.map(|num| num as usize), - Integer::U32(u32) => u32.value.map(|num| num as usize), - Integer::U64(u64) => u64.value.map(|num| num as usize), - Integer::U128(u128) => u128.value.map(|num| num as usize), + Integer::U8(u8) => u8.value.map(|num| num as u128), + Integer::U16(u16) => u16.value.map(|num| num as u128), + Integer::U32(u32) => u32.value.map(|num| num as u128), + Integer::U64(u64) => u64.value.map(|num| num as u128), + Integer::U128(u128) => u128.value.map(|num| num as u128), }; match option { Some(number) => write!(f, "{}{}", number, self.get_type()), diff --git a/types/src/program.rs b/types/src/program.rs index da78f99b43..94e8ad1c64 100644 --- a/types/src/program.rs +++ b/types/src/program.rs @@ -59,9 +59,9 @@ impl<'ast> Program { } impl Program { - pub fn new() -> Self { + pub fn new(name: String) -> Self { Self { - name: "".into(), + name, expected_inputs: vec![], imports: vec![], circuits: HashMap::new(), diff --git a/types/src/statements/statement.rs b/types/src/statements/statement.rs index ca8a416a33..2929d548c4 100644 --- a/types/src/statements/statement.rs +++ b/types/src/statements/statement.rs @@ -30,24 +30,34 @@ pub enum Statement { impl<'ast> From> for Statement { fn from(statement: ReturnStatement<'ast>) -> Self { + let span = Span::from(statement.span); Statement::Return( statement .expressions .into_iter() - .map(|expression| Expression::from(expression)) + .map(|expression| { + let mut expression = Expression::from(expression); + expression.set_span(&span); + + expression + }) .collect(), - Span::from(statement.span), + span, ) } } impl<'ast> From> for Statement { fn from(statement: DefinitionStatement<'ast>) -> Self { + let span = Span::from(statement.span); + let mut expression = Expression::from(statement.expression); + expression.set_span(&span); + Statement::Definition( Declare::from(statement.declare), Variable::from(statement.variable), - Expression::from(statement.expression), - Span::from(statement.span), + expression, + span, ) } } @@ -141,12 +151,12 @@ impl<'ast> From> for Statement { fn from(statement: ForStatement<'ast>) -> Self { let from = match Expression::from(statement.start) { Expression::Integer(number) => number, - Expression::Implicit(string) => Integer::from_implicit(string), + Expression::Implicit(string, _span) => Integer::from_implicit(string), expression => unimplemented!("Range bounds should be integers, found {}", expression), }; let to = match Expression::from(statement.stop) { Expression::Integer(number) => number, - Expression::Implicit(string) => Integer::from_implicit(string), + Expression::Implicit(string, _span) => Integer::from_implicit(string), expression => unimplemented!("Range bounds should be integers, found {}", expression), }; @@ -178,7 +188,12 @@ impl<'ast> From> for Statement { impl<'ast> From> for Statement { fn from(statement: ExpressionStatement<'ast>) -> Self { - Statement::Expression(Expression::from(statement.expression), Span::from(statement.span)) + let span = Span::from(statement.span); + let mut expression = Expression::from(statement.expression); + + expression.set_span(&span); + + Statement::Expression(expression, span) } } diff --git a/types/src/types/type_.rs b/types/src/types/type_.rs index 47e24ec51c..bed59bb394 100644 --- a/types/src/types/type_.rs +++ b/types/src/types/type_.rs @@ -15,6 +15,22 @@ pub enum Type { SelfType, } +impl Type { + pub fn is_self(&self) -> bool { + if let Type::SelfType = self { + return true; + } + false + } + + pub fn is_circuit(&self) -> bool { + if let Type::Circuit(_) = self { + return true; + } + false + } +} + /// pest ast -> Explicit Type for defining circuit members and function params impl From for Type { @@ -60,29 +76,29 @@ impl<'ast> From> for Type { impl Type { pub fn outer_dimension(&self, dimensions: &Vec) -> Self { - let _type = self.clone(); + let type_ = self.clone(); if dimensions.len() > 1 { let mut next = vec![]; next.extend_from_slice(&dimensions[1..]); - return Type::Array(Box::new(_type), next); + return Type::Array(Box::new(type_), next); } - _type + type_ } pub fn inner_dimension(&self, dimensions: &Vec) -> Self { - let _type = self.clone(); + let type_ = self.clone(); if dimensions.len() > 1 { let mut next = vec![]; next.extend_from_slice(&dimensions[..dimensions.len() - 1]); - return Type::Array(Box::new(_type), next); + return Type::Array(Box::new(type_), next); } - _type + type_ } } @@ -93,8 +109,8 @@ impl fmt::Display for Type { Type::Field => write!(f, "field"), Type::Group => write!(f, "group"), Type::Boolean => write!(f, "bool"), - Type::Circuit(ref variable) => write!(f, "{}", variable), - Type::SelfType => write!(f, "Self"), + Type::Circuit(ref variable) => write!(f, "circuit {}", variable), + Type::SelfType => write!(f, "SelfType"), Type::Array(ref array, ref dimensions) => { write!(f, "{}", *array)?; for row in dimensions {