From 4775ae1fc9d0aff776954289d1ac50e6b40b92c9 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 15:03:21 -0300 Subject: [PATCH 1/2] Add `Expr::as_unary` --- .../src/hir/comptime/interpreter/builtin.rs | 41 ++++++++++++++++++- noir_stdlib/src/meta/expr.nr | 4 ++ noir_stdlib/src/meta/mod.nr | 1 + noir_stdlib/src/meta/op.nr | 21 ++++++++++ .../comptime_exp/src/main.nr | 17 ++++++++ 5 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 noir_stdlib/src/meta/op.nr diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 330a6efaac3..5bb0f436537 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -17,8 +17,8 @@ use rustc_hash::FxHashMap as HashMap; use crate::{ ast::{ - ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, Literal, UnresolvedType, - UnresolvedTypeData, Visibility, + ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, Literal, UnaryOp, + UnresolvedType, UnresolvedTypeData, Visibility, }, hir::comptime::{errors::IResult, value::add_token_spans, InterpreterError, Value}, hir_def::function::FunctionBody, @@ -51,6 +51,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_function_call" => expr_as_function_call(arguments, return_type, location), "expr_as_if" => expr_as_if(arguments, return_type, location), "expr_as_index" => expr_as_index(arguments, return_type, location), + "expr_as_unary_op" => expr_as_unary_op(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), "is_unconstrained" => Ok(Value::Bool(true)), "function_def_name" => function_def_name(interner, arguments, location), @@ -837,6 +838,42 @@ fn expr_as_index( }) } +// fn as_unary_op(self) -> Option<(UnaryOp, Expr)> +fn expr_as_unary_op( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type.clone(), location, |expr| { + if let ExpressionKind::Prefix(prefix_expr) = expr { + let option_type = extract_option_generic_type(return_type); + let Type::Tuple(mut tuple_types) = option_type else { + panic!("Expected the return type option generic arg to be a tuple"); + }; + assert_eq!(tuple_types.len(), 2); + + tuple_types.pop().unwrap(); + let unary_op_type = tuple_types.pop().unwrap(); + + let unary_op_value = match prefix_expr.operator { + UnaryOp::Minus => 0_u128, + UnaryOp::Not => 1_u128, + UnaryOp::MutableReference => 2_u128, + UnaryOp::Dereference { .. } => 3_u128, + }; + + let mut fields = HashMap::default(); + fields.insert(Rc::new("op".to_string()), Value::Field(unary_op_value.into())); + + let unary_op = Value::Struct(fields, unary_op_type); + let rhs = Value::Expr(prefix_expr.rhs.kind); + Some(Value::Tuple(vec![unary_op, rhs])) + } else { + None + } + }) +} + // fn as_tuple(self) -> Option<[Expr]> fn expr_as_tuple( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index df375fa97d3..3230ce42457 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -1,4 +1,5 @@ use crate::option::Option; +use crate::meta::op::UnaryOp; impl Expr { #[builtin(expr_as_bool)] @@ -15,4 +16,7 @@ impl Expr { #[builtin(expr_as_tuple)] fn as_tuple(self) -> Option<[Expr]> {} + + #[builtin(expr_as_unary_op)] + fn as_unary_op(self) -> Option<(UnaryOp, Expr)> {} } diff --git a/noir_stdlib/src/meta/mod.nr b/noir_stdlib/src/meta/mod.nr index e081d4ecd4b..beaee8e44ea 100644 --- a/noir_stdlib/src/meta/mod.nr +++ b/noir_stdlib/src/meta/mod.nr @@ -5,6 +5,7 @@ use crate::hash::poseidon2::Poseidon2Hasher; mod expr; mod function_def; mod module; +mod op; mod struct_def; mod trait_constraint; mod trait_def; diff --git a/noir_stdlib/src/meta/op.nr b/noir_stdlib/src/meta/op.nr new file mode 100644 index 00000000000..1fbd4884841 --- /dev/null +++ b/noir_stdlib/src/meta/op.nr @@ -0,0 +1,21 @@ +struct UnaryOp { + op: Field +} + +impl UnaryOp { + fn is_minus(self) -> bool { + self.op == 0 + } + + fn is_not(self) -> bool { + self.op == 1 + } + + fn is_mutable_reference(self) -> bool { + self.op == 2 + } + + fn is_dereference(self) -> bool { + self.op == 3 + } +} diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr index 339b8ecdce6..eb0d27e2a38 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -34,5 +34,22 @@ fn main() { let expr = quote { true }.as_expr().unwrap(); assert_eq(expr.as_bool().unwrap(), true); + + // Check Expr::as_unary_op + let expr = quote { -x }.as_expr().unwrap(); + let (op, _) = expr.as_unary_op().unwrap(); + assert(op.is_minus()); + + let expr = quote { !x }.as_expr().unwrap(); + let (op, _) = expr.as_unary_op().unwrap(); + assert(op.is_not()); + + let expr = quote { &mut x }.as_expr().unwrap(); + let (op, _) = expr.as_unary_op().unwrap(); + assert(op.is_mutable_reference()); + + let expr = quote { *x }.as_expr().unwrap(); + let (op, _) = expr.as_unary_op().unwrap(); + assert(op.is_dereference()); } } From 5cd6fdae498818e582c9ae02c07987583d78afb4 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 15:05:59 -0300 Subject: [PATCH 2/2] Add a comment --- compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 5bb0f436537..4ed72cc0263 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -855,6 +855,7 @@ fn expr_as_unary_op( tuple_types.pop().unwrap(); let unary_op_type = tuple_types.pop().unwrap(); + // These values should match the values used in noir_stdlib/src/meta/op.nr let unary_op_value = match prefix_expr.operator { UnaryOp::Minus => 0_u128, UnaryOp::Not => 1_u128,