From 3f29da467609c5c3cffb945cb9c410153fb683da Mon Sep 17 00:00:00 2001 From: devy Date: Fri, 15 Mar 2024 22:46:06 -0600 Subject: [PATCH 1/4] added error messages for passing oracles and references from unconstrained to constrained functions --- compiler/noirc_evaluator/src/errors.rs | 3 +++ compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs | 8 +++++--- compiler/noirc_frontend/src/hir/type_check/errors.rs | 5 +++++ compiler/noirc_frontend/src/hir/type_check/expr.rs | 11 +++++++++++ .../compile_failure/unconstrained_oracle/Nargo.toml | 5 +++++ .../compile_failure/unconstrained_oracle/src/main.nr | 9 +++++++++ .../compile_failure/unconstrained_ref/Nargo.toml | 5 +++++ .../compile_failure/unconstrained_ref/src/main.nr | 8 ++++++++ .../compile_failure/unconstrained_slice/Nargo.toml | 5 +++++ .../compile_failure/unconstrained_slice/src/main.nr | 11 +++++++++++ 10 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 test_programs/compile_failure/unconstrained_oracle/Nargo.toml create mode 100644 test_programs/compile_failure/unconstrained_oracle/src/main.nr create mode 100644 test_programs/compile_failure/unconstrained_ref/Nargo.toml create mode 100644 test_programs/compile_failure/unconstrained_ref/src/main.nr create mode 100644 test_programs/compile_failure/unconstrained_slice/Nargo.toml create mode 100644 test_programs/compile_failure/unconstrained_slice/src/main.nr diff --git a/compiler/noirc_evaluator/src/errors.rs b/compiler/noirc_evaluator/src/errors.rs index 40f4336e0b5..06259e06248 100644 --- a/compiler/noirc_evaluator/src/errors.rs +++ b/compiler/noirc_evaluator/src/errors.rs @@ -48,6 +48,8 @@ pub enum RuntimeError { BigIntModulus { call_stack: CallStack }, #[error("Slices cannot be returned from an unconstrained runtime to a constrained runtime")] UnconstrainedSliceReturnToConstrained { call_stack: CallStack }, + #[error("All `oracle` methods should be wrapped in an unconstrained fn")] + UnconstrainedOracleReturnToConstrained { call_stack: CallStack }, } // We avoid showing the actual lhs and rhs since most of the time they are just 0 @@ -139,6 +141,7 @@ impl RuntimeError { | RuntimeError::NestedSlice { call_stack, .. } | RuntimeError::BigIntModulus { call_stack, .. } | RuntimeError::UnconstrainedSliceReturnToConstrained { call_stack } => call_stack, + RuntimeError::UnconstrainedOracleReturnToConstrained { call_stack } => call_stack, } } } diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 8d4d0668534..4db32d8c869 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -612,9 +612,11 @@ impl Context { self.ssa_values.insert(*result, output); } } - Value::ForeignFunction(_) => unreachable!( - "All `oracle` methods should be wrapped in an unconstrained fn" - ), + Value::ForeignFunction(_) => { + return Err(RuntimeError::UnconstrainedOracleReturnToConstrained { + call_stack: self.acir_context.get_call_stack(), + }) + } _ => unreachable!("expected calling a function but got {function_value:?}"), } } diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index cba2400441f..70741f10c7e 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -120,6 +120,10 @@ pub enum TypeCheckError { "Cannot pass a mutable reference from a constrained runtime to an unconstrained runtime" )] ConstrainedReferenceToUnconstrained { span: Span }, + #[error( + "Cannot pass a mutable reference from a unconstrained runtime to an constrained runtime" + )] + UnconstrainedReferenceToConstrained { span: Span }, #[error("Slices cannot be returned from an unconstrained runtime to a constrained runtime")] UnconstrainedSliceReturnToConstrained { span: Span }, #[error("Only sized types may be used in the entry point to a program")] @@ -213,6 +217,7 @@ impl From for Diagnostic { | TypeCheckError::OverflowingAssignment { span, .. } | TypeCheckError::FieldModulo { span } | TypeCheckError::ConstrainedReferenceToUnconstrained { span } + | TypeCheckError::UnconstrainedReferenceToConstrained { span } | TypeCheckError::UnconstrainedSliceReturnToConstrained { span } => { Diagnostic::simple_error(error.to_string(), String::new(), span) } diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index c5287d35caf..49a4c01137a 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -194,6 +194,17 @@ impl<'interner> TypeChecker<'interner> { return Type::Error; } + // Check that we are not passing a reference from an unconstrained runtime to a constrained runtime + if is_current_func_constrained + && is_unconstrained_call + && matches!(&return_type.follow_bindings(), Type::MutableReference(_)) + { + self.errors.push(TypeCheckError::UnconstrainedReferenceToConstrained { + span: self.interner.expr_span(expr_id), + }); + return Type::Error; + } + return_type } HirExpression::MethodCall(mut method_call) => { diff --git a/test_programs/compile_failure/unconstrained_oracle/Nargo.toml b/test_programs/compile_failure/unconstrained_oracle/Nargo.toml new file mode 100644 index 00000000000..1081b5ab8e2 --- /dev/null +++ b/test_programs/compile_failure/unconstrained_oracle/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "unconstrained_oracle" +type = "bin" +authors = [""] +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_failure/unconstrained_oracle/src/main.nr b/test_programs/compile_failure/unconstrained_oracle/src/main.nr new file mode 100644 index 00000000000..abc7bf51ab8 --- /dev/null +++ b/test_programs/compile_failure/unconstrained_oracle/src/main.nr @@ -0,0 +1,9 @@ +#[oracle(getNoun)] +unconstrained fn external_fn() -> Field { + 100 / 5 +} + +fn main() { + let x = anon(); + assert(x * 5 == 100); +} diff --git a/test_programs/compile_failure/unconstrained_ref/Nargo.toml b/test_programs/compile_failure/unconstrained_ref/Nargo.toml new file mode 100644 index 00000000000..b120a3b5532 --- /dev/null +++ b/test_programs/compile_failure/unconstrained_ref/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "unconstrained_ref" +type = "bin" +authors = [""] +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_failure/unconstrained_ref/src/main.nr b/test_programs/compile_failure/unconstrained_ref/src/main.nr new file mode 100644 index 00000000000..bb4b2090ddb --- /dev/null +++ b/test_programs/compile_failure/unconstrained_ref/src/main.nr @@ -0,0 +1,8 @@ +unconstrained fn uncon_ref() -> &mut Field { + let lr = &mut 7; + lr +} + +fn main() { + let e = uncon_ref(); +} \ No newline at end of file diff --git a/test_programs/compile_failure/unconstrained_slice/Nargo.toml b/test_programs/compile_failure/unconstrained_slice/Nargo.toml new file mode 100644 index 00000000000..bf44af03bd2 --- /dev/null +++ b/test_programs/compile_failure/unconstrained_slice/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "unconstrained_slice" +type = "bin" +authors = [""] +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_failure/unconstrained_slice/src/main.nr b/test_programs/compile_failure/unconstrained_slice/src/main.nr new file mode 100644 index 00000000000..b42006efc4e --- /dev/null +++ b/test_programs/compile_failure/unconstrained_slice/src/main.nr @@ -0,0 +1,11 @@ +unconstrained fn uncon_slice() -> [Field] { + let mut slice: [Field] = [0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice +} + +fn main() { + let e = uncon_slice(); + e +} From 158af81783b1498f2bdb89dacc5decbba5efcf17 Mon Sep 17 00:00:00 2001 From: devy Date: Mon, 18 Mar 2024 12:32:58 -0600 Subject: [PATCH 2/4] updates --- .../noirc_frontend/src/hir/type_check/expr.rs | 31 ++++++++----------- .../unconstrained_slice/Nargo.toml | 5 --- .../unconstrained_slice/src/main.nr | 11 ------- 3 files changed, 13 insertions(+), 34 deletions(-) delete mode 100644 test_programs/compile_failure/unconstrained_slice/Nargo.toml delete mode 100644 test_programs/compile_failure/unconstrained_slice/src/main.nr diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index 49a4c01137a..ac42cf7463e 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -184,25 +184,20 @@ impl<'interner> TypeChecker<'interner> { let return_type = self.bind_function_type(function, args, span); // Check that we are not passing a slice from an unconstrained runtime to a constrained runtime - if is_current_func_constrained - && is_unconstrained_call - && return_type.contains_slice() + if is_current_func_constrained && is_unconstrained_call && return_type.contains_slice() || + is_current_func_constrained && is_unconstrained_call && matches!(&return_type.follow_bindings(), Type::MutableReference(_)) { - self.errors.push(TypeCheckError::UnconstrainedSliceReturnToConstrained { - span: self.interner.expr_span(expr_id), - }); - return Type::Error; - } - - // Check that we are not passing a reference from an unconstrained runtime to a constrained runtime - if is_current_func_constrained - && is_unconstrained_call - && matches!(&return_type.follow_bindings(), Type::MutableReference(_)) - { - self.errors.push(TypeCheckError::UnconstrainedReferenceToConstrained { - span: self.interner.expr_span(expr_id), - }); - return Type::Error; + if return_type.contains_slice() { + self.errors.push(TypeCheckError::UnconstrainedSliceReturnToConstrained { + span: self.interner.expr_span(expr_id), + }); + return Type::Error; + } else if matches!(&return_type.follow_bindings(), Type::MutableReference(_)) { + self.errors.push(TypeCheckError::UnconstrainedReferenceToConstrained { + span: self.interner.expr_span(expr_id), + }); + return Type::Error; + } } return_type diff --git a/test_programs/compile_failure/unconstrained_slice/Nargo.toml b/test_programs/compile_failure/unconstrained_slice/Nargo.toml deleted file mode 100644 index bf44af03bd2..00000000000 --- a/test_programs/compile_failure/unconstrained_slice/Nargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[package] -name = "unconstrained_slice" -type = "bin" -authors = [""] -[dependencies] \ No newline at end of file diff --git a/test_programs/compile_failure/unconstrained_slice/src/main.nr b/test_programs/compile_failure/unconstrained_slice/src/main.nr deleted file mode 100644 index b42006efc4e..00000000000 --- a/test_programs/compile_failure/unconstrained_slice/src/main.nr +++ /dev/null @@ -1,11 +0,0 @@ -unconstrained fn uncon_slice() -> [Field] { - let mut slice: [Field] = [0; 2]; - - let mut new_slice = slice.push_back(6); - new_slice -} - -fn main() { - let e = uncon_slice(); - e -} From 7fda9dfae093a400f4232e40bdf5c46f18a5065f Mon Sep 17 00:00:00 2001 From: devy Date: Mon, 18 Mar 2024 12:40:33 -0600 Subject: [PATCH 3/4] updates --- compiler/noirc_frontend/src/hir/type_check/expr.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index ac42cf7463e..c46b3b347d2 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -184,8 +184,7 @@ impl<'interner> TypeChecker<'interner> { let return_type = self.bind_function_type(function, args, span); // Check that we are not passing a slice from an unconstrained runtime to a constrained runtime - if is_current_func_constrained && is_unconstrained_call && return_type.contains_slice() || - is_current_func_constrained && is_unconstrained_call && matches!(&return_type.follow_bindings(), Type::MutableReference(_)) + if is_current_func_constrained && is_unconstrained_call { if return_type.contains_slice() { self.errors.push(TypeCheckError::UnconstrainedSliceReturnToConstrained { From be9310fca36a832dcd29562422dc9590f17a78cd Mon Sep 17 00:00:00 2001 From: devy Date: Mon, 18 Mar 2024 12:43:27 -0600 Subject: [PATCH 4/4] updates --- compiler/noirc_frontend/src/hir/type_check/expr.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index c46b3b347d2..3be02f5aeef 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -184,8 +184,7 @@ impl<'interner> TypeChecker<'interner> { let return_type = self.bind_function_type(function, args, span); // Check that we are not passing a slice from an unconstrained runtime to a constrained runtime - if is_current_func_constrained && is_unconstrained_call - { + if is_current_func_constrained && is_unconstrained_call { if return_type.contains_slice() { self.errors.push(TypeCheckError::UnconstrainedSliceReturnToConstrained { span: self.interner.expr_span(expr_id),