From 09320ecae8bae4011d38094fde0a3eaf5b16fd6b Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 11:55:43 -0500 Subject: [PATCH 1/9] Fix a couple issues --- .../noirc_frontend/src/elaborator/comptime.rs | 22 ++++++++++ .../src/elaborator/expressions.rs | 23 ++++++----- compiler/noirc_frontend/src/elaborator/mod.rs | 18 ++++++--- .../src/elaborator/statements.rs | 9 +---- .../src/hir/resolution/errors.rs | 9 +++++ noir_stdlib/src/append.nr | 4 +- noir_stdlib/src/meta/expr.nr | 40 +++++++++---------- noir_stdlib/src/meta/op.nr | 4 +- .../quote_at_runtime/Nargo.toml | 7 ++++ .../quote_at_runtime/src/main.nr | 7 ++++ .../comptime_global_using_trait/Nargo.toml | 7 ++++ .../comptime_global_using_trait/src/main.nr | 4 ++ 12 files changed, 107 insertions(+), 47 deletions(-) create mode 100644 test_programs/compile_failure/quote_at_runtime/Nargo.toml create mode 100644 test_programs/compile_failure/quote_at_runtime/src/main.nr create mode 100644 test_programs/compile_success_empty/comptime_global_using_trait/Nargo.toml create mode 100644 test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 240c48fd260..8d1bb37ff89 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -159,6 +159,7 @@ impl<'context> Elaborator<'context> { generated_items: &mut CollectedItems, ) { if let SecondaryAttribute::Custom(attribute) = attribute { + self.function_context.push(FunctionContext::default()); if let Err(error) = self.run_comptime_attribute_name_on_item( &attribute.contents, item.clone(), @@ -169,6 +170,7 @@ impl<'context> Elaborator<'context> { ) { self.errors.push(error); } + self.check_and_pop_function_context(); } } @@ -517,6 +519,7 @@ impl<'context> Elaborator<'context> { module_attributes: &[ModuleAttribute], ) -> CollectedItems { let mut generated_items = CollectedItems::default(); + self.in_comptime_context_override = true; for (trait_id, trait_) in traits { let attributes = &trait_.trait_def.attributes; @@ -550,6 +553,7 @@ impl<'context> Elaborator<'context> { self.run_attributes_on_modules(module_attributes, &mut generated_items); + self.in_comptime_context_override = false; generated_items } @@ -599,4 +603,22 @@ impl<'context> Elaborator<'context> { } } } + + /// Perform the given function in a comptime context. + /// This will set the `in_comptime_context` flag on `self` as well as + /// push a new function context to resolve any trait constraints early. + pub(super) fn elaborate_in_comptime_context(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { + let old_comptime_value = std::mem::replace(&mut self.in_comptime_context_override, true); + // We have to push a new FunctionContext so that we can resolve any constraints + // in this comptime block early before the function as a whole finishes elaborating. + // Otherwise the interpreter below may find expressions for which the underlying trait + // call is not yet solved for. + self.function_context.push(Default::default()); + + let result = f(self); + + self.check_and_pop_function_context(); + self.in_comptime_context_override = old_comptime_value; + result + } } diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index beede7a3a30..04c9cbfb594 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -54,7 +54,7 @@ impl<'context> Elaborator<'context> { ExpressionKind::Tuple(tuple) => self.elaborate_tuple(tuple), ExpressionKind::Lambda(lambda) => self.elaborate_lambda(*lambda), ExpressionKind::Parenthesized(expr) => return self.elaborate_expression(*expr), - ExpressionKind::Quote(quote) => self.elaborate_quote(quote), + ExpressionKind::Quote(quote) => self.elaborate_quote(quote, expr.span), ExpressionKind::Comptime(comptime, _) => { return self.elaborate_comptime_block(comptime, expr.span) } @@ -735,20 +735,21 @@ impl<'context> Elaborator<'context> { (expr, Type::Function(arg_types, Box::new(body_type), Box::new(env_type), false)) } - fn elaborate_quote(&mut self, mut tokens: Tokens) -> (HirExpression, Type) { + fn elaborate_quote(&mut self, mut tokens: Tokens, span: Span) -> (HirExpression, Type) { tokens = self.find_unquoted_exprs_tokens(tokens); - (HirExpression::Quote(tokens), Type::Quoted(QuotedType::Quoted)) + + if self.in_comptime_context() { + (HirExpression::Quote(tokens), Type::Quoted(QuotedType::Quoted)) + } else { + self.push_err(ResolverError::QuoteInRuntimeCode { span }); + (HirExpression::Error, Type::Quoted(QuotedType::Quoted)) + } } fn elaborate_comptime_block(&mut self, block: BlockExpression, span: Span) -> (ExprId, Type) { - // We have to push a new FunctionContext so that we can resolve any constraints - // in this comptime block early before the function as a whole finishes elaborating. - // Otherwise the interpreter below may find expressions for which the underlying trait - // call is not yet solved for. - self.function_context.push(Default::default()); - let (block, _typ) = self.elaborate_block_expression(block); - - self.check_and_pop_function_context(); + let (block, _typ) = + self.elaborate_in_comptime_context(|this| this.elaborate_block_expression(block)); + let mut interpreter = self.setup_interpreter(); let value = interpreter.evaluate_block(block); let (id, typ) = self.inline_comptime_value(value, span); diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index dd8e985d3a2..0ed50c42059 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -158,6 +158,10 @@ pub struct Elaborator<'context> { /// Initially empty, it is set whenever a new top-level item is resolved. local_module: LocalModuleId, + /// True if we're elaborating a comptime item such as a comptime function, + /// block, global, or attribute. + in_comptime_context_override: bool, + crate_id: CrateId, /// The scope of --debug-comptime, or None if unset @@ -215,6 +219,7 @@ impl<'context> Elaborator<'context> { unresolved_globals: BTreeMap::new(), current_trait: None, interpreter_call_stack, + in_comptime_context_override: false, } } @@ -1289,7 +1294,12 @@ impl<'context> Elaborator<'context> { let comptime = let_stmt.comptime; - let (let_statement, _typ) = self.elaborate_let(let_stmt, Some(global_id)); + let (let_statement, _typ) = if comptime { + self.elaborate_in_comptime_context(|this| this.elaborate_let(let_stmt, Some(global_id))) + } else { + self.elaborate_let(let_stmt, Some(global_id)) + }; + let statement_id = self.interner.get_global(global_id).let_statement; self.interner.replace_statement(statement_id, let_statement); @@ -1324,9 +1334,7 @@ impl<'context> Elaborator<'context> { .lookup_id(definition_id, location) .expect("The global should be defined since evaluate_let did not error"); - self.debug_comptime(location, |interner| { - interner.get_global(global_id).let_statement.to_display_ast(interner).kind - }); + self.debug_comptime(location, |interner| value.display(interner).to_string()); self.interner.get_global_mut(global_id).value = Some(value); } @@ -1427,7 +1435,7 @@ impl<'context> Elaborator<'context> { fn in_comptime_context(&self) -> bool { // The first context is the global context, followed by the function-specific context. // Any context after that is a `comptime {}` block's. - if self.function_context.len() > 2 { + if self.in_comptime_context_override || self.function_context.len() > 2 { return true; } diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index d7d330f891a..9e29978a9d5 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -441,14 +441,9 @@ impl<'context> Elaborator<'context> { } fn elaborate_comptime_statement(&mut self, statement: Statement) -> (HirStatement, Type) { - // We have to push a new FunctionContext so that we can resolve any constraints - // in this comptime block early before the function as a whole finishes elaborating. - // Otherwise the interpreter below may find expressions for which the underlying trait - // call is not yet solved for. - self.function_context.push(Default::default()); let span = statement.span; - let (hir_statement, _typ) = self.elaborate_statement(statement); - self.check_and_pop_function_context(); + let (hir_statement, _typ) = + self.elaborate_in_comptime_context(|this| this.elaborate_statement(statement)); let mut interpreter = self.setup_interpreter(); let value = interpreter.evaluate_statement(hir_statement); let (expr, typ) = self.inline_comptime_value(value, span); diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index e74468bdf18..5abc94b89a2 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -124,6 +124,8 @@ pub enum ResolverError { AssociatedConstantsMustBeNumeric { span: Span }, #[error("Overflow in `{lhs} {op} {rhs}`")] OverflowInType { lhs: u32, op: crate::BinaryTypeOperator, rhs: u32, span: Span }, + #[error("`quote` cannot be used in runtime code")] + QuoteInRuntimeCode { span: Span }, } impl ResolverError { @@ -504,6 +506,13 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *span, ) } + ResolverError::QuoteInRuntimeCode { span } => { + Diagnostic::simple_error( + "`quote` cannot be used in runtime code".to_string(), + "Wrap this in a `comptime` block or function to use it".to_string(), + *span, + ) + }, } } } diff --git a/noir_stdlib/src/append.nr b/noir_stdlib/src/append.nr index 4577ae199b8..22baa9205a0 100644 --- a/noir_stdlib/src/append.nr +++ b/noir_stdlib/src/append.nr @@ -25,11 +25,11 @@ impl Append for [T] { } impl Append for Quoted { - fn empty() -> Self { + comptime fn empty() -> Self { quote {} } - fn append(self, other: Self) -> Self { + comptime fn append(self, other: Self) -> Self { quote { $self $other } } } diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 43638ad791b..52f9db9ba32 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -153,7 +153,7 @@ impl Expr { } // docs:start:quoted - fn quoted(self) -> Quoted { + comptime fn quoted(self) -> Quoted { // docs:end:quoted quote { $self } } @@ -364,12 +364,12 @@ fn modify_expressions(exprs: [Expr], f: fn[Env](Expr) -> Option) -> [ exprs.map(|expr: Expr| expr.modify(f)) } -fn new_array(exprs: [Expr]) -> Expr { +comptime fn new_array(exprs: [Expr]) -> Expr { let exprs = join_expressions(exprs, quote { , }); quote { [$exprs]}.as_expr().unwrap() } -fn new_assert(predicate: Expr, msg: Option) -> Expr { +comptime fn new_assert(predicate: Expr, msg: Option) -> Expr { if msg.is_some() { let msg = msg.unwrap(); quote { assert($predicate, $msg) }.as_expr().unwrap() @@ -378,7 +378,7 @@ fn new_assert(predicate: Expr, msg: Option) -> Expr { } } -fn new_assert_eq(lhs: Expr, rhs: Expr, msg: Option) -> Expr { +comptime fn new_assert_eq(lhs: Expr, rhs: Expr, msg: Option) -> Expr { if msg.is_some() { let msg = msg.unwrap(); quote { assert_eq($lhs, $rhs, $msg) }.as_expr().unwrap() @@ -387,30 +387,30 @@ fn new_assert_eq(lhs: Expr, rhs: Expr, msg: Option) -> Expr { } } -fn new_assign(lhs: Expr, rhs: Expr) -> Expr { +comptime fn new_assign(lhs: Expr, rhs: Expr) -> Expr { quote { $lhs = $rhs }.as_expr().unwrap() } -fn new_binary_op(lhs: Expr, op: BinaryOp, rhs: Expr) -> Expr { +comptime fn new_binary_op(lhs: Expr, op: BinaryOp, rhs: Expr) -> Expr { let op = op.quoted(); quote { ($lhs) $op ($rhs) }.as_expr().unwrap() } -fn new_block(exprs: [Expr]) -> Expr { +comptime fn new_block(exprs: [Expr]) -> Expr { let exprs = join_expressions(exprs, quote { ; }); quote { { $exprs }}.as_expr().unwrap() } -fn new_cast(expr: Expr, typ: UnresolvedType) -> Expr { +comptime fn new_cast(expr: Expr, typ: UnresolvedType) -> Expr { quote { ($expr) as $typ }.as_expr().unwrap() } -fn new_comptime(exprs: [Expr]) -> Expr { +comptime fn new_comptime(exprs: [Expr]) -> Expr { let exprs = join_expressions(exprs, quote { ; }); quote { comptime { $exprs }}.as_expr().unwrap() } -fn new_if(condition: Expr, consequence: Expr, alternative: Option) -> Expr { +comptime fn new_if(condition: Expr, consequence: Expr, alternative: Option) -> Expr { if alternative.is_some() { let alternative = alternative.unwrap(); quote { if $condition { $consequence } else { $alternative }}.as_expr().unwrap() @@ -419,21 +419,21 @@ fn new_if(condition: Expr, consequence: Expr, alternative: Option) -> Expr } } -fn new_index(object: Expr, index: Expr) -> Expr { +comptime fn new_index(object: Expr, index: Expr) -> Expr { quote { $object[$index] }.as_expr().unwrap() } -fn new_member_access(object: Expr, name: Quoted) -> Expr { +comptime fn new_member_access(object: Expr, name: Quoted) -> Expr { quote { $object.$name }.as_expr().unwrap() } -fn new_function_call(function: Expr, arguments: [Expr]) -> Expr { +comptime fn new_function_call(function: Expr, arguments: [Expr]) -> Expr { let arguments = join_expressions(arguments, quote { , }); quote { $function($arguments) }.as_expr().unwrap() } -fn new_method_call(object: Expr, name: Quoted, generics: [UnresolvedType], arguments: [Expr]) -> Expr { +comptime fn new_method_call(object: Expr, name: Quoted, generics: [UnresolvedType], arguments: [Expr]) -> Expr { let arguments = join_expressions(arguments, quote { , }); if generics.len() == 0 { @@ -444,30 +444,30 @@ fn new_method_call(object: Expr, name: Quoted, generics: [UnresolvedType], argum } } -fn new_repeated_element_array(expr: Expr, length: Expr) -> Expr { +comptime fn new_repeated_element_array(expr: Expr, length: Expr) -> Expr { quote { [$expr; $length] }.as_expr().unwrap() } -fn new_repeated_element_slice(expr: Expr, length: Expr) -> Expr { +comptime fn new_repeated_element_slice(expr: Expr, length: Expr) -> Expr { quote { &[$expr; $length] }.as_expr().unwrap() } -fn new_slice(exprs: [Expr]) -> Expr { +comptime fn new_slice(exprs: [Expr]) -> Expr { let exprs = join_expressions(exprs, quote { , }); quote { &[$exprs]}.as_expr().unwrap() } -fn new_tuple(exprs: [Expr]) -> Expr { +comptime fn new_tuple(exprs: [Expr]) -> Expr { let exprs = join_expressions(exprs, quote { , }); quote { ($exprs) }.as_expr().unwrap() } -fn new_unary_op(op: UnaryOp, rhs: Expr) -> Expr { +comptime fn new_unary_op(op: UnaryOp, rhs: Expr) -> Expr { let op = op.quoted(); quote { $op($rhs) }.as_expr().unwrap() } -fn new_unsafe(exprs: [Expr]) -> Expr { +comptime fn new_unsafe(exprs: [Expr]) -> Expr { let exprs = join_expressions(exprs, quote { ; }); quote { unsafe { $exprs }}.as_expr().unwrap() } diff --git a/noir_stdlib/src/meta/op.nr b/noir_stdlib/src/meta/op.nr index 1917a04da59..4b104486201 100644 --- a/noir_stdlib/src/meta/op.nr +++ b/noir_stdlib/src/meta/op.nr @@ -28,7 +28,7 @@ impl UnaryOp { } // docs:start:unary_quoted - pub fn quoted(self) -> Quoted { + pub comptime fn quoted(self) -> Quoted { // docs:end:unary_quoted if self.is_minus() { quote { - } @@ -147,7 +147,7 @@ impl BinaryOp { } // docs:start:binary_quoted - pub fn quoted(self) -> Quoted { + pub comptime fn quoted(self) -> Quoted { // docs:end:binary_quoted if self.is_add() { quote { + } diff --git a/test_programs/compile_failure/quote_at_runtime/Nargo.toml b/test_programs/compile_failure/quote_at_runtime/Nargo.toml new file mode 100644 index 00000000000..3ce62412b32 --- /dev/null +++ b/test_programs/compile_failure/quote_at_runtime/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "quote_at_runtime" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] diff --git a/test_programs/compile_failure/quote_at_runtime/src/main.nr b/test_programs/compile_failure/quote_at_runtime/src/main.nr new file mode 100644 index 00000000000..5da409682f6 --- /dev/null +++ b/test_programs/compile_failure/quote_at_runtime/src/main.nr @@ -0,0 +1,7 @@ +fn main() { + foo(quote { test }) +} + +fn foo(q: Quoted) { + println(q); +} diff --git a/test_programs/compile_success_empty/comptime_global_using_trait/Nargo.toml b/test_programs/compile_success_empty/comptime_global_using_trait/Nargo.toml new file mode 100644 index 00000000000..2de6e4d149e --- /dev/null +++ b/test_programs/compile_success_empty/comptime_global_using_trait/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "comptime_global_using_trait" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] diff --git a/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr b/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr new file mode 100644 index 00000000000..f10c4180673 --- /dev/null +++ b/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr @@ -0,0 +1,4 @@ + +comptime global FOO: i32 = Default::default(); + +fn main() {} From d0b651d7768660a07f4c81b2d5d1d89fe14ebbcd Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 12:02:23 -0500 Subject: [PATCH 2/9] Rename flag --- .../noirc_frontend/src/elaborator/comptime.rs | 24 +++++++++++++++---- compiler/noirc_frontend/src/elaborator/mod.rs | 19 ++------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 8d1bb37ff89..e7c043d6689 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -519,7 +519,7 @@ impl<'context> Elaborator<'context> { module_attributes: &[ModuleAttribute], ) -> CollectedItems { let mut generated_items = CollectedItems::default(); - self.in_comptime_context_override = true; + self.in_comptime_context = true; for (trait_id, trait_) in traits { let attributes = &trait_.trait_def.attributes; @@ -553,7 +553,7 @@ impl<'context> Elaborator<'context> { self.run_attributes_on_modules(module_attributes, &mut generated_items); - self.in_comptime_context_override = false; + self.in_comptime_context = false; generated_items } @@ -608,7 +608,7 @@ impl<'context> Elaborator<'context> { /// This will set the `in_comptime_context` flag on `self` as well as /// push a new function context to resolve any trait constraints early. pub(super) fn elaborate_in_comptime_context(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { - let old_comptime_value = std::mem::replace(&mut self.in_comptime_context_override, true); + let old_comptime_value = std::mem::replace(&mut self.in_comptime_context, true); // We have to push a new FunctionContext so that we can resolve any constraints // in this comptime block early before the function as a whole finishes elaborating. // Otherwise the interpreter below may find expressions for which the underlying trait @@ -618,7 +618,23 @@ impl<'context> Elaborator<'context> { let result = f(self); self.check_and_pop_function_context(); - self.in_comptime_context_override = old_comptime_value; + self.in_comptime_context = old_comptime_value; result } + + /// True if we're currently within a `comptime` block, function, or global + pub(super) fn in_comptime_context(&self) -> bool { + if self.in_comptime_context { + return true; + } + + self.in_comptime_context + || match self.current_item { + Some(DependencyId::Function(id)) => { + self.interner.function_modifiers(&id).is_comptime + } + Some(DependencyId::Global(id)) => self.interner.get_global_definition(id).comptime, + _ => false, + } + } } diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 0ed50c42059..6871152edb5 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -160,7 +160,7 @@ pub struct Elaborator<'context> { /// True if we're elaborating a comptime item such as a comptime function, /// block, global, or attribute. - in_comptime_context_override: bool, + in_comptime_context: bool, crate_id: CrateId, @@ -219,7 +219,7 @@ impl<'context> Elaborator<'context> { unresolved_globals: BTreeMap::new(), current_trait: None, interpreter_call_stack, - in_comptime_context_override: false, + in_comptime_context: false, } } @@ -1431,21 +1431,6 @@ impl<'context> Elaborator<'context> { } } - /// True if we're currently within a `comptime` block, function, or global - fn in_comptime_context(&self) -> bool { - // The first context is the global context, followed by the function-specific context. - // Any context after that is a `comptime {}` block's. - if self.in_comptime_context_override || self.function_context.len() > 2 { - return true; - } - - match self.current_item { - Some(DependencyId::Function(id)) => self.interner.function_modifiers(&id).is_comptime, - Some(DependencyId::Global(id)) => self.interner.get_global_definition(id).comptime, - _ => false, - } - } - /// True if we're currently within a constrained function. /// Defaults to `true` if the current function is unknown. fn in_constrained_function(&self) -> bool { From c797d5a7147bce861f6465b5994d22c2c6c7b715 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 12:06:44 -0500 Subject: [PATCH 3/9] Format --- .../comptime_global_using_trait/src/main.nr | 1 - 1 file changed, 1 deletion(-) diff --git a/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr b/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr index f10c4180673..a1a2c4b125a 100644 --- a/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr +++ b/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr @@ -1,4 +1,3 @@ - comptime global FOO: i32 = Default::default(); fn main() {} From 2f01d61f183324d7eea2453e6baa6158465a5d2c Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 12:16:43 -0500 Subject: [PATCH 4/9] Macro args are also comptime context --- .../noirc_frontend/src/elaborator/comptime.rs | 26 +++++++++---------- .../src/elaborator/expressions.rs | 8 +++++- .../inject_context_attribute/src/main.nr | 4 +-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index e7c043d6689..9a53d16dacf 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -159,18 +159,18 @@ impl<'context> Elaborator<'context> { generated_items: &mut CollectedItems, ) { if let SecondaryAttribute::Custom(attribute) = attribute { - self.function_context.push(FunctionContext::default()); - if let Err(error) = self.run_comptime_attribute_name_on_item( - &attribute.contents, - item.clone(), - span, - attribute.contents_span, - attribute_context, - generated_items, - ) { - self.errors.push(error); - } - self.check_and_pop_function_context(); + self.elaborate_in_comptime_context(|this| { + if let Err(error) = this.run_comptime_attribute_name_on_item( + &attribute.contents, + item.clone(), + span, + attribute.contents_span, + attribute_context, + generated_items, + ) { + this.errors.push(error); + } + }); } } @@ -519,7 +519,6 @@ impl<'context> Elaborator<'context> { module_attributes: &[ModuleAttribute], ) -> CollectedItems { let mut generated_items = CollectedItems::default(); - self.in_comptime_context = true; for (trait_id, trait_) in traits { let attributes = &trait_.trait_def.attributes; @@ -553,7 +552,6 @@ impl<'context> Elaborator<'context> { self.run_attributes_on_modules(module_attributes, &mut generated_items); - self.in_comptime_context = false; generated_items } diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 04c9cbfb594..15d6ed5506b 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -307,7 +307,13 @@ impl<'context> Elaborator<'context> { let mut arguments = Vec::with_capacity(call.arguments.len()); let args = vecmap(call.arguments, |arg| { let span = arg.span; - let (arg, typ) = self.elaborate_expression(arg); + + let (arg, typ) = if call.is_macro_call { + self.elaborate_in_comptime_context(|this| this.elaborate_expression(arg)) + } else { + self.elaborate_expression(arg) + }; + arguments.push(arg); (typ, arg, span) }); diff --git a/test_programs/compile_success_empty/inject_context_attribute/src/main.nr b/test_programs/compile_success_empty/inject_context_attribute/src/main.nr index 26be3135133..9dc8cf1ed47 100644 --- a/test_programs/compile_success_empty/inject_context_attribute/src/main.nr +++ b/test_programs/compile_success_empty/inject_context_attribute/src/main.nr @@ -28,7 +28,7 @@ fn zero() -> Field { 0 } -fn inject_context(f: FunctionDefinition) { +comptime fn inject_context(f: FunctionDefinition) { // Add a `_context: Context` parameter to the function let parameters = f.parameters(); let parameters = parameters.push_front((quote { _context }, quote { Context }.as_type())); @@ -39,7 +39,7 @@ fn inject_context(f: FunctionDefinition) { f.set_body(body); } -fn mapping_function(expr: Expr, f: FunctionDefinition) -> Option { +comptime fn mapping_function(expr: Expr, f: FunctionDefinition) -> Option { expr.as_function_call().and_then( |func_call: (Expr, [Expr])| { let (name, arguments) = func_call; From 5b9409f4348b0947091ddd4f3e4943c471ff5d89 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 12:17:56 -0500 Subject: [PATCH 5/9] Format --- compiler/noirc_frontend/src/elaborator/comptime.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 9a53d16dacf..c2347adcbee 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -622,10 +622,6 @@ impl<'context> Elaborator<'context> { /// True if we're currently within a `comptime` block, function, or global pub(super) fn in_comptime_context(&self) -> bool { - if self.in_comptime_context { - return true; - } - self.in_comptime_context || match self.current_item { Some(DependencyId::Function(id)) => { From edbffe87639f49ac3e7d8fcbfc50378eaaf55440 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 12:24:17 -0500 Subject: [PATCH 6/9] More comptime --- .../compile_success_empty/attributes_struct/src/main.nr | 2 +- .../comptime_function_definition/src/main.nr | 2 +- .../compile_success_empty/comptime_module/src/main.nr | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test_programs/compile_success_empty/attributes_struct/src/main.nr b/test_programs/compile_success_empty/attributes_struct/src/main.nr index 25c9402035c..79bf3e29533 100644 --- a/test_programs/compile_success_empty/attributes_struct/src/main.nr +++ b/test_programs/compile_success_empty/attributes_struct/src/main.nr @@ -14,7 +14,7 @@ struct Foo { } -fn add_attribute(s: StructDefinition) { +comptime fn add_attribute(s: StructDefinition) { assert(!s.has_named_attribute(quote { foo })); s.add_attribute("foo"); assert(s.has_named_attribute(quote { foo })); diff --git a/test_programs/compile_success_empty/comptime_function_definition/src/main.nr b/test_programs/compile_success_empty/comptime_function_definition/src/main.nr index 62f119cc0c0..6bfd8ef9699 100644 --- a/test_programs/compile_success_empty/comptime_function_definition/src/main.nr +++ b/test_programs/compile_success_empty/comptime_function_definition/src/main.nr @@ -74,7 +74,7 @@ mod foo { #[attr] pub fn some() {} - fn attr(f: FunctionDefinition) { + comptime fn attr(f: FunctionDefinition) { assert_eq(f.module().name(), quote { foo }); assert(!f.is_unconstrained()); diff --git a/test_programs/compile_success_empty/comptime_module/src/main.nr b/test_programs/compile_success_empty/comptime_module/src/main.nr index baf45c517ed..90a42fede5b 100644 --- a/test_programs/compile_success_empty/comptime_module/src/main.nr +++ b/test_programs/compile_success_empty/comptime_module/src/main.nr @@ -25,19 +25,19 @@ fn increment_counter() { counter += 1; } -fn outer_attribute_func(m: Module) -> Quoted { +comptime fn outer_attribute_func(m: Module) -> Quoted { assert_eq(m.name(), quote { yet_another_module }); increment_counter(); quote { pub fn generated_outer_function() {} } } -fn inner_attribute_func(m: Module) -> Quoted { +comptime fn inner_attribute_func(m: Module) -> Quoted { assert_eq(m.name(), quote { yet_another_module }); increment_counter(); quote { pub fn generated_inner_function() {} } } -fn outer_attribute_separate_module(m: Module) { +comptime fn outer_attribute_separate_module(m: Module) { assert_eq(m.name(), quote { separate_module }); increment_counter(); } @@ -49,7 +49,7 @@ mod add_to_me { fn add_to_me_function() {} } -fn add_function(m: Module) { +comptime fn add_function(m: Module) { m.add_item( quote { pub fn added_function() -> super::Foo { add_to_me_function(); From be03f5d4c6369bd26446bde71bd6569836684af1 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 12:40:59 -0500 Subject: [PATCH 7/9] Fix tests --- compiler/noirc_frontend/src/tests.rs | 2 +- .../comptime_module/src/separate_module.nr | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 1a0f086b484..64c9b7471b4 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -3373,7 +3373,7 @@ fn unquoted_integer_as_integer_token() { #[attr] pub fn foobar() {} - fn attr(_f: FunctionDefinition) -> Quoted { + comptime fn attr(_f: FunctionDefinition) -> Quoted { let serialized_len = 1; // We are testing that when we unquote $serialized_len, it's unquoted // as the token `1` and not as something else that later won't be parsed correctly diff --git a/test_programs/compile_success_empty/comptime_module/src/separate_module.nr b/test_programs/compile_success_empty/comptime_module/src/separate_module.nr index 53784101507..c1aeac4622c 100644 --- a/test_programs/compile_success_empty/comptime_module/src/separate_module.nr +++ b/test_programs/compile_success_empty/comptime_module/src/separate_module.nr @@ -1,5 +1,6 @@ #![inner_attribute_separate_module] -fn inner_attribute_separate_module(m: Module) { + +comptime fn inner_attribute_separate_module(m: Module) { assert_eq(m.name(), quote { separate_module }); super::increment_counter(); } From 45de99b380ad7c341592760099c7e10ca5f3ddee Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 12:48:52 -0500 Subject: [PATCH 8/9] Fix comptime_module --- .../compile_success_empty/comptime_module/src/main.nr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_programs/compile_success_empty/comptime_module/src/main.nr b/test_programs/compile_success_empty/comptime_module/src/main.nr index 90a42fede5b..4412722b476 100644 --- a/test_programs/compile_success_empty/comptime_module/src/main.nr +++ b/test_programs/compile_success_empty/comptime_module/src/main.nr @@ -21,7 +21,7 @@ mod separate_module; comptime mut global counter = 0; -fn increment_counter() { +comptime fn increment_counter() { counter += 1; } @@ -85,6 +85,7 @@ fn main() { assert(another_module.has_named_attribute(quote { some_attribute })); } + println(counter); assert_eq(counter, 4); yet_another_module::generated_outer_function(); From e5c2b04010a7fd51aa45896b2a6646f6796df994 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 9 Sep 2024 13:04:39 -0500 Subject: [PATCH 9/9] Remove println --- test_programs/compile_success_empty/comptime_module/src/main.nr | 1 - 1 file changed, 1 deletion(-) diff --git a/test_programs/compile_success_empty/comptime_module/src/main.nr b/test_programs/compile_success_empty/comptime_module/src/main.nr index 4412722b476..c3ba7ba4643 100644 --- a/test_programs/compile_success_empty/comptime_module/src/main.nr +++ b/test_programs/compile_success_empty/comptime_module/src/main.nr @@ -85,7 +85,6 @@ fn main() { assert(another_module.has_named_attribute(quote { some_attribute })); } - println(counter); assert_eq(counter, 4); yet_another_module::generated_outer_function();