From 7bcdcc4f14a02f1c464a497d1a2d83450b93d6d2 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 22 Aug 2024 14:30:23 -0300 Subject: [PATCH 1/5] Add `Expr::as_unsafe` and `Expr::as_comptime` --- .../src/hir/comptime/interpreter/builtin.rs | 40 +++++++++++++++++++ noir_stdlib/src/meta/expr.nr | 26 ++++++++++++ 2 files changed, 66 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 1303ca83e1f..2ca8b8d967b 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -55,6 +55,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_binary_op" => expr_as_binary_op(arguments, return_type, location), "expr_as_block" => expr_as_block(arguments, return_type, location), "expr_as_bool" => expr_as_bool(arguments, return_type, location), + "expr_as_comptime" => expr_as_comptime(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), @@ -69,6 +70,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_slice" => expr_as_slice(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), "expr_as_unary_op" => expr_as_unary_op(arguments, return_type, location), + "expr_as_unsafe" => expr_as_unsafe(arguments, return_type, location), "expr_has_semicolon" => expr_has_semicolon(arguments, location), "is_unconstrained" => Ok(Value::Bool(true)), "function_def_name" => function_def_name(interner, arguments, location), @@ -859,6 +861,25 @@ fn expr_as_bool( }) } +// fn as_comptime(self) -> Option<[Expr]> +fn expr_as_comptime( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExprValue::Expression(ExpressionKind::Comptime(block_expr, _)) = expr { + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + let statements = block_expr.statements.into_iter(); + let statements = statements.map(|statement| Value::statement(statement.kind)).collect(); + + Some(Value::Slice(statements, typ)) + } else { + None + } + }) +} + // fn as_function_call(self) -> Option<(Expr, [Expr])> fn expr_as_function_call( arguments: Vec<(Value, Location)>, @@ -1081,6 +1102,25 @@ fn expr_as_unary_op( }) } +// fn as_unsafe(self) -> Option<[Expr]> +fn expr_as_unsafe( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExprValue::Expression(ExpressionKind::Unsafe(block_expr, _)) = expr { + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + let statements = block_expr.statements.into_iter(); + let statements = statements.map(|statement| Value::statement(statement.kind)).collect(); + + Some(Value::Slice(statements, typ)) + } else { + None + } + }) +} + // fn as_has_semicolon(self) -> bool fn expr_has_semicolon(arguments: Vec<(Value, Location)>, location: Location) -> IResult { let self_argument = check_one_argument(arguments, location)?; diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 64678b58eae..513adce2ffc 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -18,6 +18,9 @@ impl Expr { #[builtin(expr_as_bool)] fn as_bool(self) -> Option {} + #[builtin(expr_as_comptime)] + fn as_comptime(self) -> Option<[Expr]> {} + #[builtin(expr_as_function_call)] fn as_function_call(self) -> Option<(Expr, [Expr])> {} @@ -45,6 +48,9 @@ impl Expr { #[builtin(expr_as_unary_op)] fn as_unary_op(self) -> Option<(UnaryOp, Expr)> {} + #[builtin(expr_as_unsafe)] + fn as_unsafe(self) -> Option<[Expr]> {} + #[builtin(expr_has_semicolon)] fn has_semicolon(self) -> bool {} } @@ -128,6 +134,16 @@ mod tests { } } + #[test] + fn test_expr_as_comptime() { + comptime + { + let expr = quote { comptime { 1; 4; 23 } }.as_expr().unwrap(); + let exprs = expr.as_comptime().unwrap(); + assert_eq(exprs.len(), 3); + } + } + #[test] fn test_expr_as_function_call() { comptime @@ -228,6 +244,16 @@ mod tests { } } + #[test] + fn test_expr_as_unsafe() { + comptime + { + let expr = quote { unsafe { 1; 4; 23 } }.as_expr().unwrap(); + let exprs = expr.as_unsafe().unwrap(); + assert_eq(exprs.len(), 3); + } + } + #[test] fn test_automatically_unwraps_parenthesized_expression() { comptime From 766e0bbeaa28b640aaa07445991a467e5e40a7e4 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 22 Aug 2024 14:32:53 -0300 Subject: [PATCH 2/5] Extract `block_expression_to_value` --- .../src/hir/comptime/interpreter/builtin.rs | 28 ++++++------------- .../interpreter/builtin/builtin_helpers.rs | 10 ++++++- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 2ca8b8d967b..3d59f29b754 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -5,11 +5,11 @@ use std::{ use acvm::{AcirField, FieldElement}; use builtin_helpers::{ - check_argument_count, check_function_not_yet_resolved, check_one_argument, - check_three_arguments, check_two_arguments, get_expr, get_function_def, get_module, get_quoted, - get_slice, get_struct, get_trait_constraint, get_trait_def, get_trait_impl, get_tuple, - get_type, get_u32, hir_pattern_to_tokens, mutate_func_meta_type, parse, parse_tokens, - replace_func_meta_parameters, replace_func_meta_return_type, + block_expression_to_value, check_argument_count, check_function_not_yet_resolved, + check_one_argument, check_three_arguments, check_two_arguments, get_expr, get_function_def, + get_module, get_quoted, get_slice, get_struct, get_trait_constraint, get_trait_def, + get_trait_impl, get_tuple, get_type, get_u32, hir_pattern_to_tokens, mutate_func_meta_type, + parse, parse_tokens, replace_func_meta_parameters, replace_func_meta_return_type, }; use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; @@ -835,11 +835,7 @@ fn expr_as_block( ) -> IResult { expr_as(arguments, return_type, location, |expr| { if let ExprValue::Expression(ExpressionKind::Block(block_expr)) = expr { - let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); - let statements = block_expr.statements.into_iter(); - let statements = statements.map(|statement| Value::statement(statement.kind)).collect(); - - Some(Value::Slice(statements, typ)) + Some(block_expression_to_value(block_expr)) } else { None } @@ -869,11 +865,7 @@ fn expr_as_comptime( ) -> IResult { expr_as(arguments, return_type, location, |expr| { if let ExprValue::Expression(ExpressionKind::Comptime(block_expr, _)) = expr { - let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); - let statements = block_expr.statements.into_iter(); - let statements = statements.map(|statement| Value::statement(statement.kind)).collect(); - - Some(Value::Slice(statements, typ)) + Some(block_expression_to_value(block_expr)) } else { None } @@ -1110,11 +1102,7 @@ fn expr_as_unsafe( ) -> IResult { expr_as(arguments, return_type, location, |expr| { if let ExprValue::Expression(ExpressionKind::Unsafe(block_expr, _)) = expr { - let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); - let statements = block_expr.statements.into_iter(); - let statements = statements.map(|statement| Value::statement(statement.kind)).collect(); - - Some(Value::Slice(statements, typ)) + Some(block_expression_to_value(block_expr)) } else { None } diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs index 81abc4e76fa..d2d65e69a99 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs @@ -4,7 +4,7 @@ use acvm::FieldElement; use noirc_errors::Location; use crate::{ - ast::{IntegerBitSize, Signedness}, + ast::{BlockExpression, IntegerBitSize, Signedness}, hir::{ comptime::{ errors::IResult, @@ -350,3 +350,11 @@ pub(super) fn replace_func_meta_return_type(typ: &mut Type, return_type: Type) { _ => {} } } + +pub(super) fn block_expression_to_value(block_expr: BlockExpression) -> Value { + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + let statements = block_expr.statements.into_iter(); + let statements = statements.map(|statement| Value::statement(statement.kind)).collect(); + + Value::Slice(statements, typ) +} From 3339a78b09b74bfaab9fc0183da9b01b7a002577 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 22 Aug 2024 14:55:52 -0300 Subject: [PATCH 3/5] Make it work for comptime statements --- .../src/hir/comptime/interpreter/builtin.rs | 23 +++++++++++++++++-- noir_stdlib/src/meta/expr.nr | 13 +++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 3d59f29b754..9709bd83d84 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -11,14 +11,15 @@ use builtin_helpers::{ get_trait_impl, get_tuple, get_type, get_u32, hir_pattern_to_tokens, mutate_func_meta_type, parse, parse_tokens, replace_func_meta_parameters, replace_func_meta_return_type, }; +use im::Vector; use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; use rustc_hash::FxHashMap as HashMap; use crate::{ ast::{ - ArrayLiteral, ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, Literal, - StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility, + ArrayLiteral, Expression, ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, + Literal, StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility, }, hir::comptime::{ errors::IResult, @@ -866,6 +867,24 @@ fn expr_as_comptime( expr_as(arguments, return_type, location, |expr| { if let ExprValue::Expression(ExpressionKind::Comptime(block_expr, _)) = expr { Some(block_expression_to_value(block_expr)) + } else if let ExprValue::Statement(StatementKind::Comptime(statement)) = expr { + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + + // comptime { ... } as a statement wraps a block expression, + // and in that case we return the block expression statements + // (comptime as a statement can also be comptime for, but in that case we'll + // return the for statement as a single expression) + if let StatementKind::Expression(Expression { + kind: ExpressionKind::Block(block_expr), + .. + }) = statement.kind + { + Some(block_expression_to_value(block_expr)) + } else { + let mut elements = Vector::new(); + elements.push_back(Value::statement(statement.kind)); + Some(Value::Slice(elements, typ)) + } } else { None } diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 513adce2ffc..072cb379eb9 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -144,6 +144,19 @@ mod tests { } } + #[test] + fn test_expr_as_comptime_as_statement() { + comptime + { + let expr = quote { { comptime { 1; 4; 23 } } }.as_expr().unwrap(); + let exprs = expr.as_block().unwrap(); + assert_eq(exprs.len(), 1); + + let exprs = exprs[0].as_comptime().unwrap(); + assert_eq(exprs.len(), 3); + } + } + #[test] fn test_expr_as_function_call() { comptime From 7a20b92a24e502cadfa4a1f352b9cd1475d5c811 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 22 Aug 2024 15:02:51 -0300 Subject: [PATCH 4/5] Add `Expr::is_break` and `Expr::is_continue` --- .../src/hir/comptime/interpreter/builtin.rs | 16 ++++++++++++ noir_stdlib/src/meta/expr.nr | 26 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 9709bd83d84..10f7221ee24 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -73,6 +73,8 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_unary_op" => expr_as_unary_op(arguments, return_type, location), "expr_as_unsafe" => expr_as_unsafe(arguments, return_type, location), "expr_has_semicolon" => expr_has_semicolon(arguments, location), + "expr_is_break" => expr_is_break(arguments, location), + "expr_is_continue" => expr_is_continue(arguments, location), "is_unconstrained" => Ok(Value::Bool(true)), "function_def_name" => function_def_name(interner, arguments, location), "function_def_parameters" => function_def_parameters(interner, arguments, location), @@ -1135,6 +1137,20 @@ fn expr_has_semicolon(arguments: Vec<(Value, Location)>, location: Location) -> Ok(Value::Bool(matches!(expr_value, ExprValue::Statement(StatementKind::Semi(..))))) } +// fn is_break(self) -> bool +fn expr_is_break(arguments: Vec<(Value, Location)>, location: Location) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let expr_value = get_expr(self_argument)?; + Ok(Value::Bool(matches!(expr_value, ExprValue::Statement(StatementKind::Break)))) +} + +// fn is_continue(self) -> bool +fn expr_is_continue(arguments: Vec<(Value, Location)>, location: Location) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let expr_value = get_expr(self_argument)?; + Ok(Value::Bool(matches!(expr_value, ExprValue::Statement(StatementKind::Continue)))) +} + // Helper function for implementing the `expr_as_...` functions. fn expr_as( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 072cb379eb9..ad4fe5df094 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -53,6 +53,12 @@ impl Expr { #[builtin(expr_has_semicolon)] fn has_semicolon(self) -> bool {} + + #[builtin(expr_is_break)] + fn is_break(self) -> bool {} + + #[builtin(expr_is_continue)] + fn is_continue(self) -> bool {} } mod tests { @@ -267,6 +273,26 @@ mod tests { } } + #[test] + fn test_expr_is_break() { + comptime + { + let expr = quote { { break; } }.as_expr().unwrap(); + let exprs = expr.as_block().unwrap(); + assert(exprs[0].is_break()); + } + } + + #[test] + fn test_expr_is_continue() { + comptime + { + let expr = quote { { continue; } }.as_expr().unwrap(); + let exprs = expr.as_block().unwrap(); + assert(exprs[0].is_continue()); + } + } + #[test] fn test_automatically_unwraps_parenthesized_expression() { comptime From 10af7da495c46e89aa6be923450f321bd9da0d2f Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 22 Aug 2024 15:35:43 -0300 Subject: [PATCH 5/5] Try to reduce the number of lines --- .../src/hir/comptime/interpreter/builtin.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 10f7221ee24..a4081009309 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -866,6 +866,8 @@ fn expr_as_comptime( return_type: Type, location: Location, ) -> IResult { + use ExpressionKind::Block; + expr_as(arguments, return_type, location, |expr| { if let ExprValue::Expression(ExpressionKind::Comptime(block_expr, _)) = expr { Some(block_expression_to_value(block_expr)) @@ -876,12 +878,9 @@ fn expr_as_comptime( // and in that case we return the block expression statements // (comptime as a statement can also be comptime for, but in that case we'll // return the for statement as a single expression) - if let StatementKind::Expression(Expression { - kind: ExpressionKind::Block(block_expr), - .. - }) = statement.kind + if let StatementKind::Expression(Expression { kind: Block(block), .. }) = statement.kind { - Some(block_expression_to_value(block_expr)) + Some(block_expression_to_value(block)) } else { let mut elements = Vector::new(); elements.push_back(Value::statement(statement.kind));