From ca75cc2e35530c82cef3b86edf99a232f88b11e8 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 14:27:36 -0300 Subject: [PATCH] feat: add `Expr::as_bool` (#5729) # Description ## Problem Part of #5668 ## Summary Just one method because while doing it I got an error trying to compare two bools at comptime, and I found that that case was missing. ## Additional Context ## Documentation Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. - [x] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- .../src/hir/comptime/interpreter.rs | 2 ++ .../src/hir/comptime/interpreter/builtin.rs | 18 +++++++++++++++++- noir_stdlib/src/meta/expr.nr | 3 +++ .../comptime_exp/src/main.nr | 7 +++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 093dc370eb6..33f8c9d8332 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -897,6 +897,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { (Value::U16(lhs), Value::U16(rhs)) => Ok(Value::Bool(lhs == rhs)), (Value::U32(lhs), Value::U32(rhs)) => Ok(Value::Bool(lhs == rhs)), (Value::U64(lhs), Value::U64(rhs)) => Ok(Value::Bool(lhs == rhs)), + (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs == rhs)), (lhs, rhs) => make_error(self, lhs, rhs, "=="), }, BinaryOpKind::NotEqual => match (lhs, rhs) { @@ -909,6 +910,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { (Value::U16(lhs), Value::U16(rhs)) => Ok(Value::Bool(lhs != rhs)), (Value::U32(lhs), Value::U32(rhs)) => Ok(Value::Bool(lhs != rhs)), (Value::U64(lhs), Value::U64(rhs)) => Ok(Value::Bool(lhs != rhs)), + (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs != rhs)), (lhs, rhs) => make_error(self, lhs, rhs, "!="), }, BinaryOpKind::Less => match (lhs, rhs) { diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index c3528434a72..330a6efaac3 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -17,7 +17,7 @@ use rustc_hash::FxHashMap as HashMap; use crate::{ ast::{ - ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, UnresolvedType, + ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, Literal, UnresolvedType, UnresolvedTypeData, Visibility, }, hir::comptime::{errors::IResult, value::add_token_spans, InterpreterError, Value}, @@ -47,6 +47,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "array_as_str_unchecked" => array_as_str_unchecked(interner, arguments, location), "array_len" => array_len(interner, arguments, location), "as_slice" => as_slice(interner, arguments, location), + "expr_as_bool" => expr_as_bool(arguments, return_type, location), "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), @@ -753,6 +754,21 @@ fn zeroed(return_type: Type) -> IResult { } } +// fn as_bool(self) -> Option +fn expr_as_bool( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Literal(Literal::Bool(bool)) = expr { + Some(Value::Bool(bool)) + } else { + None + } + }) +} + // fn as_function_call(self) -> Option<(Expr, [Expr])> fn expr_as_function_call( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 2a463ef4d86..df375fa97d3 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -1,6 +1,9 @@ use crate::option::Option; impl Expr { + #[builtin(expr_as_bool)] + fn as_bool(self) -> Option {} + #[builtin(expr_as_function_call)] fn as_function_call(self) -> Option<(Expr, [Expr])> {} 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 81531310ff5..339b8ecdce6 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -27,5 +27,12 @@ fn main() { // Check parenthesized expression is automatically unwrapped let expr = quote { ((if 1 { 2 })) }.as_expr().unwrap(); assert(expr.as_if().is_some()); + + // Check Expr::as_bool + let expr = quote { false }.as_expr().unwrap(); + assert(expr.as_bool().unwrap() == false); + + let expr = quote { true }.as_expr().unwrap(); + assert_eq(expr.as_bool().unwrap(), true); } }