From 93a174265add49f40a841a9f6d70c0a1540d8eb2 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 9 Aug 2024 17:53:25 -0300 Subject: [PATCH 1/4] Add `Quoted::as_expr` --- .../src/hir/comptime/interpreter/builtin.rs | 15 +++++++++++++++ compiler/noirc_frontend/src/hir/comptime/value.rs | 7 ++++++- noir_stdlib/src/meta/quoted.nr | 3 +++ .../compile_success_empty/comptime_exp/Nargo.toml | 7 +++++++ .../comptime_exp/src/main.nr | 6 ++++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test_programs/compile_success_empty/comptime_exp/Nargo.toml create mode 100644 test_programs/compile_success_empty/comptime_exp/src/main.nr diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 959d5908f3d..597615b871d 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -64,6 +64,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "modulus_le_bits" => modulus_le_bits(interner, arguments, location), "modulus_le_bytes" => modulus_le_bytes(interner, arguments, location), "modulus_num_bits" => modulus_num_bits(interner, arguments, location), + "quoted_as_expr" => quoted_as_expr(arguments, return_type, location), "quoted_as_module" => quoted_as_module(self, arguments, return_type, location), "quoted_as_trait_constraint" => quoted_as_trait_constraint(self, arguments, location), "quoted_as_type" => quoted_as_type(self, arguments, location), @@ -312,6 +313,20 @@ fn slice_insert( Ok(Value::Slice(values, typ)) } +// fn as_expr(quoted: Quoted) -> Option +fn quoted_as_expr( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + let argument = check_one_argument(arguments, location)?; + + let expr = parse(argument, parser::expression(), "an expression").ok(); + let value = expr.map(|expr| Value::Expr(expr.kind)); + + option(return_type, value) +} + // fn as_module(quoted: Quoted) -> Option fn quoted_as_module( interpreter: &mut Interpreter, diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 1264cd21635..d5408309e55 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -57,6 +57,7 @@ pub enum Value { ModuleDefinition(ModuleId), Type(Type), Zeroed(Type), + Expr(ExpressionKind), } impl Value { @@ -103,6 +104,7 @@ impl Value { Value::ModuleDefinition(_) => Type::Quoted(QuotedType::Module), Value::Type(_) => Type::Quoted(QuotedType::Type), Value::Zeroed(typ) => return Cow::Borrowed(typ), + Value::Expr(_) => Type::Quoted(QuotedType::Expr), }) } @@ -223,6 +225,7 @@ impl Value { } }; } + Value::Expr(expr) => expr, Value::Pointer(..) | Value::StructDefinition(_) | Value::TraitConstraint(..) @@ -345,7 +348,8 @@ impl Value { HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements))) } Value::Quoted(tokens) => HirExpression::Unquote(add_token_spans(tokens, location.span)), - Value::Pointer(..) + Value::Expr(..) + | Value::Pointer(..) | Value::StructDefinition(_) | Value::TraitConstraint(..) | Value::TraitDefinition(_) @@ -530,6 +534,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { Value::ModuleDefinition(_) => write!(f, "(module)"), Value::Zeroed(typ) => write!(f, "(zeroed {typ})"), Value::Type(typ) => write!(f, "{}", typ), + Value::Expr(expr) => write!(f, "{}", expr), } } } diff --git a/noir_stdlib/src/meta/quoted.nr b/noir_stdlib/src/meta/quoted.nr index 9c8de23258c..cccc3fe0f12 100644 --- a/noir_stdlib/src/meta/quoted.nr +++ b/noir_stdlib/src/meta/quoted.nr @@ -2,6 +2,9 @@ use crate::cmp::Eq; use crate::option::Option; impl Quoted { + #[builtin(quoted_as_expr)] + fn as_expr(self) -> Option {} + #[builtin(quoted_as_module)] fn as_module(self) -> Option {} diff --git a/test_programs/compile_success_empty/comptime_exp/Nargo.toml b/test_programs/compile_success_empty/comptime_exp/Nargo.toml new file mode 100644 index 00000000000..df36e0e05b0 --- /dev/null +++ b/test_programs/compile_success_empty/comptime_exp/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "comptime_exp" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr new file mode 100644 index 00000000000..c5f9ee0aabd --- /dev/null +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -0,0 +1,6 @@ +fn main() { + comptime + { + let _expr = quote { foo(bar) }.as_expr().unwrap(); + } +} From b7834548706f36bd49191cdef2145f0f559b0337 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 9 Aug 2024 18:16:58 -0300 Subject: [PATCH 2/4] Add `Expr::as_function_call` --- .../src/hir/comptime/interpreter/builtin.rs | 29 +++++++++++++++++-- .../interpreter/builtin/builtin_helpers.rs | 13 ++++++++- noir_stdlib/src/meta/expr.nr | 7 +++++ noir_stdlib/src/meta/mod.nr | 1 + .../comptime_exp/src/main.nr | 4 ++- 5 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 noir_stdlib/src/meta/expr.nr diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 597615b871d..9c861015bea 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -6,7 +6,7 @@ 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_function_def, get_module, get_quoted, + 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_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, @@ -17,8 +17,8 @@ use rustc_hash::FxHashMap as HashMap; use crate::{ ast::{ - FunctionKind, FunctionReturnType, IntegerBitSize, UnresolvedType, UnresolvedTypeData, - Visibility, + ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, UnresolvedType, + UnresolvedTypeData, Visibility, }, hir::comptime::{errors::IResult, value::add_token_spans, InterpreterError, Value}, hir_def::function::FunctionBody, @@ -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_function_call" => expr_as_function_call(arguments, return_type, 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), @@ -687,6 +688,28 @@ fn zeroed(return_type: Type) -> IResult { } } +// fn as_function_call(self) -> Option<(Expr, [Expr])> +fn expr_as_function_call( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let expr = get_expr(self_argument)?; + + let option_value = if let ExpressionKind::Call(call_expression) = expr { + let function = Value::Expr(call_expression.func.kind); + let arguments = call_expression.arguments.into_iter(); + let arguments = arguments.map(|argument| Value::Expr(argument.kind)).collect(); + let arguments = Value::Slice(arguments, Type::Quoted(QuotedType::Expr)); + Some(Value::Tuple(vec![function, arguments])) + } else { + None + }; + + option(return_type, option_value) +} + // fn name(self) -> Quoted fn function_def_name( interner: &NodeInterner, 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 fac2913ff79..56f6c11974f 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::{ExpressionKind, IntegerBitSize, Signedness}, hir::{ comptime::{errors::IResult, value::add_token_spans, Interpreter, InterpreterError, Value}, def_map::ModuleId, @@ -145,6 +145,17 @@ pub(crate) fn get_u32((value, location): (Value, Location)) -> IResult { } } +pub(crate) fn get_expr((value, location): (Value, Location)) -> IResult { + match value { + Value::Expr(expr) => Ok(expr), + value => { + let expected = Type::Quoted(QuotedType::Expr); + let actual = value.get_type().into_owned(); + Err(InterpreterError::TypeMismatch { expected, actual, location }) + } + } +} + pub(crate) fn get_function_def((value, location): (Value, Location)) -> IResult { match value { Value::FunctionDefinition(id) => Ok(id), diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr new file mode 100644 index 00000000000..91310aefda1 --- /dev/null +++ b/noir_stdlib/src/meta/expr.nr @@ -0,0 +1,7 @@ +use crate::cmp::Eq; +use crate::option::Option; + +impl Expr { + #[builtin(expr_as_function_call)] + fn as_function_call(self) -> Option<(Expr, [Expr])> {} +} diff --git a/noir_stdlib/src/meta/mod.nr b/noir_stdlib/src/meta/mod.nr index e00c8d41d11..2763685fd0d 100644 --- a/noir_stdlib/src/meta/mod.nr +++ b/noir_stdlib/src/meta/mod.nr @@ -2,6 +2,7 @@ use crate::collections::umap::UHashMap; use crate::hash::BuildHasherDefault; use crate::hash::poseidon2::Poseidon2Hasher; +mod expr; mod function_def; mod module; mod struct_def; 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 c5f9ee0aabd..8b6f7b480c7 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -1,6 +1,8 @@ fn main() { comptime { - let _expr = quote { foo(bar) }.as_expr().unwrap(); + let expr = quote { foo(bar) }.as_expr().unwrap(); + let (_function, args) = expr.as_function_call().unwrap(); + assert_eq(args.len(), 1); } } From e3e1def875d406746940eb30a0911151b6628b97 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 9 Aug 2024 18:19:33 -0300 Subject: [PATCH 3/4] Extract `expr_as` --- .../src/hir/comptime/interpreter/builtin.rs | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 9c861015bea..71058a74b1c 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -694,19 +694,32 @@ fn expr_as_function_call( return_type: Type, location: Location, ) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Call(call_expression) = expr { + let function = Value::Expr(call_expression.func.kind); + let arguments = call_expression.arguments.into_iter(); + let arguments = arguments.map(|argument| Value::Expr(argument.kind)).collect(); + let arguments = Value::Slice(arguments, Type::Quoted(QuotedType::Expr)); + Some(Value::Tuple(vec![function, arguments])) + } else { + None + } + }) +} + +// Helper function for implementing the `expr_as_...` functions. +fn expr_as( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, + f: F, +) -> IResult +where + F: FnOnce(ExpressionKind) -> Option, +{ let self_argument = check_one_argument(arguments, location)?; let expr = get_expr(self_argument)?; - - let option_value = if let ExpressionKind::Call(call_expression) = expr { - let function = Value::Expr(call_expression.func.kind); - let arguments = call_expression.arguments.into_iter(); - let arguments = arguments.map(|argument| Value::Expr(argument.kind)).collect(); - let arguments = Value::Slice(arguments, Type::Quoted(QuotedType::Expr)); - Some(Value::Tuple(vec![function, arguments])) - } else { - None - }; - + let option_value = f(expr); option(return_type, option_value) } From 348b01bd48b7b2f30f1b9c1ffadd2e2104f79f86 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 12 Aug 2024 11:59:06 -0300 Subject: [PATCH 4/4] Fixes from code review --- .../noirc_frontend/src/hir/comptime/interpreter/builtin.rs | 3 ++- noir_stdlib/src/meta/expr.nr | 1 - 2 files changed, 2 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 71058a74b1c..ef7b9f2be55 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -699,7 +699,8 @@ fn expr_as_function_call( let function = Value::Expr(call_expression.func.kind); let arguments = call_expression.arguments.into_iter(); let arguments = arguments.map(|argument| Value::Expr(argument.kind)).collect(); - let arguments = Value::Slice(arguments, Type::Quoted(QuotedType::Expr)); + let arguments = + Value::Slice(arguments, Type::Slice(Box::new(Type::Quoted(QuotedType::Expr)))); Some(Value::Tuple(vec![function, arguments])) } else { None diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 91310aefda1..54681632543 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -1,4 +1,3 @@ -use crate::cmp::Eq; use crate::option::Option; impl Expr {