From 5a4ec6e93b5334c8c06815ce93dc9ce83668a7ba Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Thu, 30 May 2024 15:59:13 -0500 Subject: [PATCH 01/24] Start work on elaborating comptime expressions --- compiler/noirc_frontend/src/ast/expression.rs | 8 ++- .../src/elaborator/expressions.rs | 37 ++++++++-- compiler/noirc_frontend/src/elaborator/mod.rs | 16 ++++- .../src/elaborator/statements.rs | 18 ++++- .../noirc_frontend/src/hir/comptime/errors.rs | 6 ++ .../src/hir/comptime/interpreter.rs | 39 +++-------- .../noirc_frontend/src/hir/comptime/scan.rs | 23 +----- .../noirc_frontend/src/hir/comptime/value.rs | 70 ++++++++++--------- 8 files changed, 122 insertions(+), 95 deletions(-) diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index 21131c7121..af25a16319 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -6,6 +6,7 @@ use crate::ast::{ UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, Visibility, }; use crate::token::{Attributes, Token}; +use crate::{Shared, StructType, Type}; use acvm::{acir::AcirField, FieldElement}; use iter_extended::vecmap; use noirc_errors::{Span, Spanned}; @@ -108,7 +109,7 @@ impl ExpressionKind { } pub fn constructor((type_name, fields): (Path, Vec<(Ident, Expression)>)) -> ExpressionKind { - ExpressionKind::Constructor(Box::new(ConstructorExpression { type_name, fields })) + ExpressionKind::Constructor(Box::new(ConstructorExpression { type_name, fields, struct_type: None })) } /// Returns true if the expression is a literal integer @@ -451,6 +452,11 @@ pub struct MethodCallExpression { pub struct ConstructorExpression { pub type_name: Path, pub fields: Vec<(Ident, Expression)>, + + /// This may be filled out during macro expansion + /// so that we can skip re-resolving the type name since it + /// would be lost at that point. + pub struct_type: Option<(Shared, Vec)>, } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 8acd186707..5c69610b8b 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -9,6 +9,7 @@ use crate::{ UnresolvedTypeExpression, }, hir::{ + comptime::{Interpreter, InterpreterError}, resolution::{errors::ResolverError, resolver::LambdaContext}, type_check::TypeCheckError, }, @@ -36,7 +37,10 @@ impl<'context> Elaborator<'context> { pub(super) fn elaborate_expression(&mut self, expr: Expression) -> (ExprId, Type) { let (hir_expr, typ) = match expr.kind { ExpressionKind::Literal(literal) => self.elaborate_literal(literal, expr.span), - ExpressionKind::Block(block) => self.elaborate_block(block), + ExpressionKind::Block(block) => { + let (block, typ) = self.elaborate_block(block); + (HirExpression::Block(block), typ) + } ExpressionKind::Prefix(prefix) => self.elaborate_prefix(*prefix), ExpressionKind::Index(index) => self.elaborate_index(*index), ExpressionKind::Call(call) => self.elaborate_call(*call, expr.span), @@ -58,7 +62,9 @@ impl<'context> Elaborator<'context> { ExpressionKind::Lambda(lambda) => self.elaborate_lambda(*lambda), ExpressionKind::Parenthesized(expr) => return self.elaborate_expression(*expr), ExpressionKind::Quote(quote) => self.elaborate_quote(quote), - ExpressionKind::Comptime(comptime) => self.elaborate_comptime_block(comptime), + ExpressionKind::Comptime(comptime) => { + return self.elaborate_comptime_block(comptime, expr.span) + } ExpressionKind::Error => (HirExpression::Error, Type::Error), }; let id = self.interner.push_expr(hir_expr); @@ -67,7 +73,7 @@ impl<'context> Elaborator<'context> { (id, typ) } - pub(super) fn elaborate_block(&mut self, block: BlockExpression) -> (HirExpression, Type) { + pub(super) fn elaborate_block(&mut self, block: BlockExpression) -> (HirBlockExpression, Type) { self.push_scope(); let mut block_type = Type::Unit; let mut statements = Vec::with_capacity(block.statements.len()); @@ -92,7 +98,7 @@ impl<'context> Elaborator<'context> { } self.pop_scope(); - (HirExpression::Block(HirBlockExpression { statements }), block_type) + (HirBlockExpression { statements }, block_type) } fn elaborate_literal(&mut self, literal: Literal, span: Span) -> (HirExpression, Type) { @@ -620,7 +626,26 @@ impl<'context> Elaborator<'context> { (HirExpression::Quote(block), Type::Code) } - fn elaborate_comptime_block(&mut self, _comptime: BlockExpression) -> (HirExpression, Type) { - todo!("Elaborate comptime block") + fn elaborate_comptime_block(&mut self, block: BlockExpression, span: Span) -> (ExprId, Type) { + let (block, typ) = self.elaborate_block(block); + let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); + + let make_error = |this: &mut Self, error: InterpreterError| { + this.push_err(error); + let error = this.interner.push_expr(HirExpression::Error); + this.interner.push_expr_location(error, span, self.file); + (error, Type::Error) + }; + + let value = match interpreter.evaluate_block(block) { + Ok(value) => value, + Err(error) => return make_error(self, error), + }; + + let location = Location::new(span, self.file); + match value.into_expression(self.interner, location) { + Ok(new_expr) => self.elaborate_expression(new_expr), + Err(error) => make_error(self, error), + } } } diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 594c069003..2ac3de611d 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -6,6 +6,7 @@ use std::{ use crate::{ ast::{FunctionKind, UnresolvedTraitConstraint}, hir::{ + comptime, def_collector::{ dc_crate::{ filter_literal_globals, CompilationError, ImplMap, UnresolvedGlobal, @@ -19,9 +20,12 @@ use crate::{ }, hir_def::{expr::HirIdent, function::Parameters, traits::TraitConstraint}, macros_api::{ - Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, SecondaryAttribute, StructId, + HirExpression, HirLiteral, Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, + SecondaryAttribute, StructId, + }, + node_interner::{ + DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, TraitId, TypeAliasId, }, - node_interner::{DefinitionKind, DependencyId, ExprId, FuncId, TraitId, TypeAliasId}, Shared, Type, TypeVariable, }; use crate::{ @@ -60,7 +64,7 @@ mod types; use fm::FileId; use iter_extended::vecmap; use noirc_errors::{Location, Span}; -use rustc_hash::FxHashSet as HashSet; +use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; /// ResolverMetas are tagged onto each definition to track how many times they are used #[derive(Debug, PartialEq, Eq)] @@ -153,6 +157,11 @@ pub struct Elaborator<'context> { local_module: LocalModuleId, crate_id: CrateId, + + /// Each value currently in scope in the comptime interpreter. + /// Each element of the Vec represents a scope with every scope together making + /// up all currently visible definitions. The first scope is always the global scope. + comptime_scopes: Vec>, } impl<'context> Elaborator<'context> { @@ -179,6 +188,7 @@ impl<'context> Elaborator<'context> { type_variables: Vec::new(), trait_constraints: Vec::new(), current_trait_impl: None, + comptime_scopes: vec![HashMap::default()], } } diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 40de9a3983..a16b57fddb 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -3,6 +3,7 @@ use noirc_errors::{Location, Span}; use crate::{ ast::{AssignStatement, ConstrainStatement, LValue}, hir::{ + comptime::Interpreter, resolution::errors::ResolverError, type_check::{Source, TypeCheckError}, }, @@ -13,7 +14,8 @@ use crate::{ }, }, macros_api::{ - ForLoopStatement, ForRange, HirStatement, LetStatement, Statement, StatementKind, + ForLoopStatement, ForRange, HirExpression, HirLiteral, HirStatement, LetStatement, + Statement, StatementKind, }, node_interner::{DefinitionId, DefinitionKind, GlobalId, StmtId}, Type, @@ -435,7 +437,17 @@ impl<'context> Elaborator<'context> { None } - pub(super) fn elaborate_comptime(&self, _statement: Statement) -> (HirStatement, Type) { - todo!("Comptime scanning") + pub(super) fn elaborate_comptime(&mut self, statement: Statement) -> (HirStatement, Type) { + let (hir_statement, typ) = self.elaborate_statement(statement); + let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); + + if let Err(error) = interpreter.evaluate_statement(hir_statement) { + self.push_err(error); + } + + let unit = HirExpression::Literal(HirLiteral::Unit); + let unit = self.interner.push_expr(unit); + self.interner.push_expr_type(unit, Type::Unit); + (HirStatement::Expression(unit), typ) } } diff --git a/compiler/noirc_frontend/src/hir/comptime/errors.rs b/compiler/noirc_frontend/src/hir/comptime/errors.rs index 34cecf0ece..20e3fd94b7 100644 --- a/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -52,6 +52,12 @@ pub enum InterpreterError { #[allow(unused)] pub(super) type IResult = std::result::Result; +impl From for CompilationError { + fn from(error: InterpreterError) -> Self { + CompilationError::InterpreterError(error) + } +} + impl InterpreterError { pub fn into_compilation_error_pair(self) -> (CompilationError, fm::FileId) { let location = self.get_location(); diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index c0aeb910f2..47b14ab373 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -4,7 +4,7 @@ use acvm::{acir::AcirField, FieldElement}; use im::Vector; use iter_extended::try_vecmap; use noirc_errors::Location; -use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; +use rustc_hash::FxHashMap as HashMap; use crate::ast::{BinaryOpKind, FunctionKind, IntegerBitSize, Signedness}; use crate::{ @@ -36,34 +36,18 @@ pub struct Interpreter<'interner> { /// Each value currently in scope in the interpreter. /// Each element of the Vec represents a scope with every scope together making /// up all currently visible definitions. - scopes: Vec>, - - /// True if we've expanded any macros into any functions and will need - /// to redo name resolution & type checking for that function. - changed_functions: HashSet, - - /// True if we've expanded any macros into global scope and will need - /// to redo name resolution & type checking for everything. - changed_globally: bool, + scopes: &'interner mut Vec>, in_loop: bool, - - /// True if we're currently in a compile-time context. - /// If this is false code is skipped over instead of executed. - in_comptime_context: bool, } #[allow(unused)] impl<'a> Interpreter<'a> { - pub(crate) fn new(interner: &'a mut NodeInterner) -> Self { - Self { - interner, - scopes: vec![HashMap::default()], - changed_functions: HashSet::default(), - changed_globally: false, - in_loop: false, - in_comptime_context: false, - } + pub(crate) fn new( + interner: &'a mut NodeInterner, + scopes: &'a mut Vec>, + ) -> Self { + Self { interner, scopes, in_loop: false } } pub(crate) fn call_function( @@ -468,7 +452,7 @@ impl<'a> Interpreter<'a> { } } - pub(super) fn evaluate_block(&mut self, mut block: HirBlockExpression) -> IResult { + pub fn evaluate_block(&mut self, mut block: HirBlockExpression) -> IResult { let last_statement = block.statements.pop(); self.push_scope(); @@ -1077,7 +1061,7 @@ impl<'a> Interpreter<'a> { Ok(Value::Closure(lambda, environment, typ)) } - fn evaluate_statement(&mut self, statement: StmtId) -> IResult { + pub fn evaluate_statement(&mut self, statement: StmtId) -> IResult { match self.interner.statement(&statement) { HirStatement::Let(let_) => self.evaluate_let(let_), HirStatement::Constrain(constrain) => self.evaluate_constrain(constrain), @@ -1265,9 +1249,6 @@ impl<'a> Interpreter<'a> { } pub(super) fn evaluate_comptime(&mut self, statement: StmtId) -> IResult { - let was_in_comptime = std::mem::replace(&mut self.in_comptime_context, true); - let result = self.evaluate_statement(statement); - self.in_comptime_context = was_in_comptime; - result + self.evaluate_statement(statement) } } diff --git a/compiler/noirc_frontend/src/hir/comptime/scan.rs b/compiler/noirc_frontend/src/hir/comptime/scan.rs index cc6b9aa7e9..707d7d2337 100644 --- a/compiler/noirc_frontend/src/hir/comptime/scan.rs +++ b/compiler/noirc_frontend/src/hir/comptime/scan.rs @@ -79,14 +79,7 @@ impl<'interner> Interpreter<'interner> { HirExpression::If(if_) => self.scan_if(if_), HirExpression::Tuple(tuple) => self.scan_tuple(tuple), HirExpression::Lambda(lambda) => self.scan_lambda(lambda), - HirExpression::Comptime(block) => { - let location = self.interner.expr_location(&expr); - let new_expr = - self.evaluate_block(block)?.into_expression(self.interner, location)?; - let new_expr = self.interner.expression(&new_expr); - self.interner.replace_expr(&expr, new_expr); - Ok(()) - } + HirExpression::Comptime(_block) => Ok(()), HirExpression::Quote(_) => { // This error could be detected much earlier in the compiler pipeline but // it just makes sense for the comptime code to handle comptime things. @@ -227,13 +220,7 @@ impl<'interner> Interpreter<'interner> { HirStatement::Expression(expression) => self.scan_expression(expression), HirStatement::Semi(semi) => self.scan_expression(semi), HirStatement::Error => Ok(()), - HirStatement::Comptime(comptime) => { - let location = self.interner.statement_location(comptime); - let new_expr = - self.evaluate_comptime(comptime)?.into_expression(self.interner, location)?; - self.interner.replace_statement(statement, HirStatement::Expression(new_expr)); - Ok(()) - } + HirStatement::Comptime(comptime) => Ok(()), } } @@ -247,11 +234,7 @@ impl<'interner> Interpreter<'interner> { Ok(()) } - fn inline_expression(&mut self, value: Value, expr: ExprId) -> IResult<()> { - let location = self.interner.expr_location(&expr); - let new_expr = value.into_expression(self.interner, location)?; - let new_expr = self.interner.expression(&new_expr); - self.interner.replace_expr(&expr, new_expr); + fn inline_expression(&mut self, _value: Value, _expr: ExprId) -> IResult<()> { Ok(()) } } diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 3c8b6e9244..351b771b4c 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -6,10 +6,14 @@ use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; use crate::{ - ast::{BlockExpression, Ident, IntegerBitSize, Signedness}, - hir_def::expr::{HirArrayLiteral, HirConstructorExpression, HirIdent, HirLambda, ImplKind}, - macros_api::{HirExpression, HirLiteral, NodeInterner}, - node_interner::{ExprId, FuncId}, + ast::{ + ArrayLiteral, BlockExpression, ConstructorExpression, Ident, IntegerBitSize, Signedness, + }, + hir_def::expr::{HirIdent, HirLambda, ImplKind}, + macros_api::{ + Expression, ExpressionKind, HirExpression, Literal, NodeInterner, Path, + }, + node_interner::FuncId, Shared, Type, }; use rustc_hash::FxHashMap as HashMap; @@ -78,54 +82,55 @@ impl Value { self, interner: &mut NodeInterner, location: Location, - ) -> IResult { + ) -> IResult { let typ = self.get_type().into_owned(); - let expression = match self { - Value::Unit => HirExpression::Literal(HirLiteral::Unit), - Value::Bool(value) => HirExpression::Literal(HirLiteral::Bool(value)), - Value::Field(value) => HirExpression::Literal(HirLiteral::Integer(value, false)), + let kind = match self { + Value::Unit => ExpressionKind::Literal(Literal::Unit), + Value::Bool(value) => ExpressionKind::Literal(Literal::Bool(value)), + Value::Field(value) => ExpressionKind::Literal(Literal::Integer(value, false)), Value::I8(value) => { let negative = value < 0; let value = value.abs(); let value = (value as u128).into(); - HirExpression::Literal(HirLiteral::Integer(value, negative)) + ExpressionKind::Literal(Literal::Integer(value, negative)) } Value::I16(value) => { let negative = value < 0; let value = value.abs(); let value = (value as u128).into(); - HirExpression::Literal(HirLiteral::Integer(value, negative)) + ExpressionKind::Literal(Literal::Integer(value, negative)) } Value::I32(value) => { let negative = value < 0; let value = value.abs(); let value = (value as u128).into(); - HirExpression::Literal(HirLiteral::Integer(value, negative)) + ExpressionKind::Literal(Literal::Integer(value, negative)) } Value::I64(value) => { let negative = value < 0; let value = value.abs(); let value = (value as u128).into(); - HirExpression::Literal(HirLiteral::Integer(value, negative)) + ExpressionKind::Literal(Literal::Integer(value, negative)) } Value::U8(value) => { - HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + ExpressionKind::Literal(Literal::Integer((value as u128).into(), false)) } Value::U16(value) => { - HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + ExpressionKind::Literal(Literal::Integer((value as u128).into(), false)) } Value::U32(value) => { - HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + ExpressionKind::Literal(Literal::Integer((value as u128).into(), false)) } Value::U64(value) => { - HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + ExpressionKind::Literal(Literal::Integer((value as u128).into(), false)) } - Value::String(value) => HirExpression::Literal(HirLiteral::Str(unwrap_rc(value))), + Value::String(value) => ExpressionKind::Literal(Literal::Str(unwrap_rc(value))), Value::Function(id, _typ) => { let id = interner.function_definition_id(id); let impl_kind = ImplKind::NotATraitMethod; - HirExpression::Ident(HirIdent { location, id, impl_kind }, None) + let ident = HirExpression::Ident(HirIdent { location, id, impl_kind }, None); + ExpressionKind::Hir(ident) } Value::Closure(_lambda, _env, _typ) => { // TODO: How should a closure's environment be inlined? @@ -134,7 +139,7 @@ impl Value { } Value::Tuple(fields) => { let fields = try_vecmap(fields, |field| field.into_expression(interner, location))?; - HirExpression::Tuple(fields) + ExpressionKind::Tuple(fields) } Value::Struct(fields, typ) => { let fields = try_vecmap(fields, |(name, field)| { @@ -142,37 +147,36 @@ impl Value { Ok((Ident::new(unwrap_rc(name), location.span), field)) })?; - let (r#type, struct_generics) = match typ.follow_bindings() { - Type::Struct(def, generics) => (def, generics), + let struct_type = match typ.follow_bindings() { + Type::Struct(def, generics) => Some((def, generics)), _ => return Err(InterpreterError::NonStructInConstructor { typ, location }), }; - HirExpression::Constructor(HirConstructorExpression { - r#type, - struct_generics, + // Since we've provided the struct_type, the path should be ignored. + let type_name = Path::from_single(String::new(), location.span); + ExpressionKind::Constructor(Box::new(ConstructorExpression { + type_name, fields, - }) + struct_type, + })) } Value::Array(elements, _) => { let elements = try_vecmap(elements, |elements| elements.into_expression(interner, location))?; - HirExpression::Literal(HirLiteral::Array(HirArrayLiteral::Standard(elements))) + ExpressionKind::Literal(Literal::Array(ArrayLiteral::Standard(elements))) } Value::Slice(elements, _) => { let elements = try_vecmap(elements, |elements| elements.into_expression(interner, location))?; - HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements))) + ExpressionKind::Literal(Literal::Slice(ArrayLiteral::Standard(elements))) } - Value::Code(block) => HirExpression::Unquote(unwrap_rc(block)), + Value::Code(block) => ExpressionKind::Block(unwrap_rc(block)), Value::Pointer(_) => { return Err(InterpreterError::CannotInlineMacro { value: self, location }) } }; - let id = interner.push_expr(expression); - interner.push_expr_location(id, location.span, location.file); - interner.push_expr_type(id, typ); - Ok(id) + Ok(Expression::new(kind, location.span)) } } From bfb0864f79784f6eb20d26010f7bdb5ae3800e58 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 31 May 2024 15:45:17 -0500 Subject: [PATCH 02/24] Start integrating interpreter --- compiler/noirc_frontend/src/ast/expression.rs | 17 ++++- .../src/elaborator/expressions.rs | 69 ++++++++++--------- compiler/noirc_frontend/src/elaborator/mod.rs | 3 +- .../noirc_frontend/src/elaborator/scope.rs | 2 + .../src/elaborator/statements.rs | 2 + .../noirc_frontend/src/hir/comptime/scan.rs | 2 +- .../noirc_frontend/src/hir/comptime/value.rs | 17 +++-- .../src/hir/def_collector/dc_crate.rs | 3 +- .../src/hir/resolution/resolver.rs | 3 + tooling/nargo_fmt/src/rewrite/expr.rs | 3 + 10 files changed, 73 insertions(+), 48 deletions(-) diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index af25a16319..05188950d3 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -5,8 +5,9 @@ use crate::ast::{ Ident, ItemVisibility, Path, Pattern, Recoverable, Statement, StatementKind, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, Visibility, }; +use crate::macros_api::StructId; +use crate::node_interner::ExprId; use crate::token::{Attributes, Token}; -use crate::{Shared, StructType, Type}; use acvm::{acir::AcirField, FieldElement}; use iter_extended::vecmap; use noirc_errors::{Span, Spanned}; @@ -34,6 +35,11 @@ pub enum ExpressionKind { Parenthesized(Box), Quote(BlockExpression), Comptime(BlockExpression), + + // This variant is only emitted when inlining the result of comptime + // code. It is used to translate function values back into the ast while + // guaranteeing they have the same instantiated type and definition id without resolving again. + Resolved(ExprId), Error, } @@ -109,7 +115,11 @@ impl ExpressionKind { } pub fn constructor((type_name, fields): (Path, Vec<(Ident, Expression)>)) -> ExpressionKind { - ExpressionKind::Constructor(Box::new(ConstructorExpression { type_name, fields, struct_type: None })) + ExpressionKind::Constructor(Box::new(ConstructorExpression { + type_name, + fields, + struct_type: None, + })) } /// Returns true if the expression is a literal integer @@ -456,7 +466,7 @@ pub struct ConstructorExpression { /// This may be filled out during macro expansion /// so that we can skip re-resolving the type name since it /// would be lost at that point. - pub struct_type: Option<(Shared, Vec)>, + pub struct_type: Option, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -528,6 +538,7 @@ impl Display for ExpressionKind { Quote(block) => write!(f, "quote {block}"), Comptime(block) => write!(f, "comptime {block}"), Error => write!(f, "Error"), + Resolved(_) => write!(f, "?Resolved"), } } } diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 5c69610b8b..74e31bb8dd 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -37,10 +37,7 @@ impl<'context> Elaborator<'context> { pub(super) fn elaborate_expression(&mut self, expr: Expression) -> (ExprId, Type) { let (hir_expr, typ) = match expr.kind { ExpressionKind::Literal(literal) => self.elaborate_literal(literal, expr.span), - ExpressionKind::Block(block) => { - let (block, typ) = self.elaborate_block(block); - (HirExpression::Block(block), typ) - } + ExpressionKind::Block(block) => self.elaborate_block(block), ExpressionKind::Prefix(prefix) => self.elaborate_prefix(*prefix), ExpressionKind::Index(index) => self.elaborate_index(*index), ExpressionKind::Call(call) => self.elaborate_call(*call, expr.span), @@ -65,6 +62,7 @@ impl<'context> Elaborator<'context> { ExpressionKind::Comptime(comptime) => { return self.elaborate_comptime_block(comptime, expr.span) } + ExpressionKind::Resolved(id) => return (id, self.interner.id_type(id)), ExpressionKind::Error => (HirExpression::Error, Type::Error), }; let id = self.interner.push_expr(hir_expr); @@ -73,7 +71,12 @@ impl<'context> Elaborator<'context> { (id, typ) } - pub(super) fn elaborate_block(&mut self, block: BlockExpression) -> (HirBlockExpression, Type) { + pub(super) fn elaborate_block(&mut self, block: BlockExpression) -> (HirExpression, Type) { + let (block, typ) = self.elaborate_block_expression(block); + (HirExpression::Block(block), typ) + } + + fn elaborate_block_expression(&mut self, block: BlockExpression) -> (HirBlockExpression, Type) { self.push_scope(); let mut block_type = Type::Unit; let mut statements = Vec::with_capacity(block.statements.len()); @@ -371,32 +374,34 @@ impl<'context> Elaborator<'context> { ) -> (HirExpression, Type) { let span = constructor.type_name.span(); - match self.lookup_type_or_error(constructor.type_name) { - Some(Type::Struct(r#type, struct_generics)) => { - let struct_type = r#type.clone(); - let generics = struct_generics.clone(); - - let fields = constructor.fields; - let field_types = r#type.borrow().get_fields(&struct_generics); - let fields = self.resolve_constructor_expr_fields( - struct_type.clone(), - field_types, - fields, - span, - ); - let expr = HirExpression::Constructor(HirConstructorExpression { - fields, - r#type, - struct_generics, - }); - (expr, Type::Struct(struct_type, generics)) - } - Some(typ) => { - self.push_err(ResolverError::NonStructUsedInConstructor { typ, span }); - (HirExpression::Error, Type::Error) + let (r#type, struct_generics) = if let Some(struct_id) = constructor.struct_type { + let typ = self.interner.get_struct(struct_id); + let generics = typ.borrow().instantiate(self.interner); + (typ, generics) + } else { + match self.lookup_type_or_error(constructor.type_name) { + Some(Type::Struct(r#type, struct_generics)) => (r#type, struct_generics), + Some(typ) => { + self.push_err(ResolverError::NonStructUsedInConstructor { typ, span }); + return (HirExpression::Error, Type::Error); + } + None => return (HirExpression::Error, Type::Error), } - None => (HirExpression::Error, Type::Error), - } + }; + + let struct_type = r#type.clone(); + let generics = struct_generics.clone(); + + let fields = constructor.fields; + let field_types = r#type.borrow().get_fields(&struct_generics); + let fields = + self.resolve_constructor_expr_fields(struct_type.clone(), field_types, fields, span); + let expr = HirExpression::Constructor(HirConstructorExpression { + fields, + r#type, + struct_generics, + }); + (expr, Type::Struct(struct_type, generics)) } /// Resolve all the fields of a struct constructor expression. @@ -627,13 +632,13 @@ impl<'context> Elaborator<'context> { } fn elaborate_comptime_block(&mut self, block: BlockExpression, span: Span) -> (ExprId, Type) { - let (block, typ) = self.elaborate_block(block); + let (block, _typ) = self.elaborate_block_expression(block); let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); let make_error = |this: &mut Self, error: InterpreterError| { this.push_err(error); let error = this.interner.push_expr(HirExpression::Error); - this.interner.push_expr_location(error, span, self.file); + this.interner.push_expr_location(error, span, this.file); (error, Type::Error) }; diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 2ac3de611d..73454bd532 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -20,8 +20,7 @@ use crate::{ }, hir_def::{expr::HirIdent, function::Parameters, traits::TraitConstraint}, macros_api::{ - HirExpression, HirLiteral, Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, - SecondaryAttribute, StructId, + Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, SecondaryAttribute, StructId, }, node_interner::{ DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, TraitId, TypeAliasId, diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index 6ae43bd3c4..9fd3be0a35 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -115,10 +115,12 @@ impl<'context> Elaborator<'context> { pub fn push_scope(&mut self) { self.scopes.start_scope(); + self.comptime_scopes.push(Default::default()); } pub fn pop_scope(&mut self) { let scope = self.scopes.end_scope(); + self.comptime_scopes.pop(); self.check_for_unused_variables_in_scope_tree(scope.into()); } diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index a16b57fddb..2bebcd83c8 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -438,6 +438,7 @@ impl<'context> Elaborator<'context> { } pub(super) fn elaborate_comptime(&mut self, statement: Statement) -> (HirStatement, Type) { + let span = statement.span; let (hir_statement, typ) = self.elaborate_statement(statement); let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); @@ -448,6 +449,7 @@ impl<'context> Elaborator<'context> { let unit = HirExpression::Literal(HirLiteral::Unit); let unit = self.interner.push_expr(unit); self.interner.push_expr_type(unit, Type::Unit); + self.interner.push_expr_location(unit, span, self.file); (HirStatement::Expression(unit), typ) } } diff --git a/compiler/noirc_frontend/src/hir/comptime/scan.rs b/compiler/noirc_frontend/src/hir/comptime/scan.rs index 707d7d2337..cb2e95fdce 100644 --- a/compiler/noirc_frontend/src/hir/comptime/scan.rs +++ b/compiler/noirc_frontend/src/hir/comptime/scan.rs @@ -220,7 +220,7 @@ impl<'interner> Interpreter<'interner> { HirStatement::Expression(expression) => self.scan_expression(expression), HirStatement::Semi(semi) => self.scan_expression(semi), HirStatement::Error => Ok(()), - HirStatement::Comptime(comptime) => Ok(()), + HirStatement::Comptime(_) => Ok(()), } } diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 351b771b4c..92ba99d334 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -10,9 +10,7 @@ use crate::{ ArrayLiteral, BlockExpression, ConstructorExpression, Ident, IntegerBitSize, Signedness, }, hir_def::expr::{HirIdent, HirLambda, ImplKind}, - macros_api::{ - Expression, ExpressionKind, HirExpression, Literal, NodeInterner, Path, - }, + macros_api::{Expression, ExpressionKind, HirExpression, Literal, NodeInterner, Path}, node_interner::FuncId, Shared, Type, }; @@ -83,8 +81,6 @@ impl Value { interner: &mut NodeInterner, location: Location, ) -> IResult { - let typ = self.get_type().into_owned(); - let kind = match self { Value::Unit => ExpressionKind::Literal(Literal::Unit), Value::Bool(value) => ExpressionKind::Literal(Literal::Bool(value)), @@ -126,11 +122,14 @@ impl Value { ExpressionKind::Literal(Literal::Integer((value as u128).into(), false)) } Value::String(value) => ExpressionKind::Literal(Literal::Str(unwrap_rc(value))), - Value::Function(id, _typ) => { + Value::Function(id, typ) => { let id = interner.function_definition_id(id); let impl_kind = ImplKind::NotATraitMethod; - let ident = HirExpression::Ident(HirIdent { location, id, impl_kind }, None); - ExpressionKind::Hir(ident) + let ident = HirIdent { location, id, impl_kind }; + let expr_id = interner.push_expr(HirExpression::Ident(ident, None)); + interner.push_expr_location(expr_id, location.span, location.file); + interner.push_expr_type(expr_id, typ); + ExpressionKind::Resolved(expr_id) } Value::Closure(_lambda, _env, _typ) => { // TODO: How should a closure's environment be inlined? @@ -148,7 +147,7 @@ impl Value { })?; let struct_type = match typ.follow_bindings() { - Type::Struct(def, generics) => Some((def, generics)), + Type::Struct(def, _) => Some(def.borrow().id), _ => return Err(InterpreterError::NonStructInConstructor { typ, location }), }; diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 05147af545..ecbb7f985d 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -548,7 +548,8 @@ impl ResolvedModule { /// Evaluate all `comptime` expressions in this module fn evaluate_comptime(&mut self, interner: &mut NodeInterner) { if self.count_errors() == 0 { - let mut interpreter = Interpreter::new(interner); + let mut scopes = vec![Default::default()]; + let mut interpreter = Interpreter::new(interner, &mut scopes); for (_file, global) in &self.globals { if let Err(error) = interpreter.scan_global(*global) { diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 35ba964c49..8f5e99bacb 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1637,6 +1637,9 @@ impl<'a> Resolver<'a> { // The quoted expression isn't resolved since we don't want errors if variables aren't defined ExpressionKind::Quote(block) => HirExpression::Quote(block), ExpressionKind::Comptime(block) => HirExpression::Comptime(self.resolve_block(block)), + ExpressionKind::Resolved(_) => unreachable!( + "ExpressionKind::Resolved should only be emitted by the comptime interpreter" + ), }; // If these lines are ever changed, make sure to change the early return diff --git a/tooling/nargo_fmt/src/rewrite/expr.rs b/tooling/nargo_fmt/src/rewrite/expr.rs index e5b30f99b7..9a704717ad 100644 --- a/tooling/nargo_fmt/src/rewrite/expr.rs +++ b/tooling/nargo_fmt/src/rewrite/expr.rs @@ -171,6 +171,9 @@ pub(crate) fn rewrite( format!("comptime {}", rewrite_block(visitor, block, span)) } ExpressionKind::Error => unreachable!(), + ExpressionKind::Resolved(_) => { + unreachable!("ExpressionKind::Resolved should only emitted by the comptime interpreter") + } } } From d42440d9a2b95eefa3acf0bad06ac1f787c429e1 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 3 Jun 2024 15:49:31 +0100 Subject: [PATCH 03/24] More comptime work --- .../noirc_frontend/src/elaborator/expressions.rs | 2 +- compiler/noirc_frontend/src/elaborator/mod.rs | 15 ++++++++++++++- .../noirc_frontend/src/elaborator/statements.rs | 2 +- .../src/hir/comptime/interpreter.rs | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 74e31bb8dd..b98b1383cb 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -636,7 +636,7 @@ impl<'context> Elaborator<'context> { let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); let make_error = |this: &mut Self, error: InterpreterError| { - this.push_err(error); + this.errors.push(error.into_compilation_error_pair()); let error = this.interner.push_expr(HirExpression::Error); this.interner.push_expr_location(error, span, this.file); (error, Type::Error) diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 73454bd532..5d67255e75 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ ast::{FunctionKind, UnresolvedTraitConstraint}, hir::{ - comptime, + comptime::{self, Interpreter}, def_collector::{ dc_crate::{ filter_literal_globals, CompilationError, ImplMap, UnresolvedGlobal, @@ -1238,8 +1238,21 @@ impl<'context> Elaborator<'context> { self.push_err(ResolverError::MutableGlobal { span }); } + let comptime = let_stmt.comptime; + self.elaborate_global_let(let_stmt, global_id); + if comptime { + let let_statement = self.interner.get_global_let_statement(global_id) + .expect("Let statement of global should be set by elaborate_global_let"); + + let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); + + if let Err(error) = interpreter.evaluate_let(let_statement) { + self.errors.push(error.into_compilation_error_pair()); + } + } + // Avoid defaulting the types of globals here since they may be used in any function. // Otherwise we may prematurely default to a Field inside the next function if this // global was unused there, even if it is consistently used as a u8 everywhere else. diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 2bebcd83c8..c5cf6f1bc0 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -443,7 +443,7 @@ impl<'context> Elaborator<'context> { let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); if let Err(error) = interpreter.evaluate_statement(hir_statement) { - self.push_err(error); + self.errors.push(error.into_compilation_error_pair()); } let unit = HirExpression::Literal(HirLiteral::Unit); diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 47b14ab373..82e7d70141 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -1082,7 +1082,7 @@ impl<'a> Interpreter<'a> { } } - pub(super) fn evaluate_let(&mut self, let_: HirLetStatement) -> IResult { + pub fn evaluate_let(&mut self, let_: HirLetStatement) -> IResult { let rhs = self.evaluate(let_.expression)?; let location = self.interner.expr_location(&let_.expression); self.define_pattern(&let_.pattern, &let_.r#type, rhs, location)?; From 83a9238a9c51fb5d1753938f94a04f62f9c3c4df Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 13:36:38 +0100 Subject: [PATCH 04/24] Re-add removed scanning functions --- compiler/noirc_frontend/src/elaborator/mod.rs | 92 --------------- .../noirc_frontend/src/elaborator/types.rs | 96 +++++++++++++++- .../noirc_frontend/src/hir/comptime/scan.rs | 23 +++- .../noirc_frontend/src/hir/comptime/value.rs | 107 +++++++++++++++++- 4 files changed, 218 insertions(+), 100 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 5d67255e75..1d1c567123 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -733,98 +733,6 @@ impl<'context> Elaborator<'context> { } } - fn find_numeric_generics( - parameters: &Parameters, - return_type: &Type, - ) -> Vec<(String, TypeVariable)> { - let mut found = BTreeMap::new(); - for (_, parameter, _) in ¶meters.0 { - Self::find_numeric_generics_in_type(parameter, &mut found); - } - Self::find_numeric_generics_in_type(return_type, &mut found); - found.into_iter().collect() - } - - fn find_numeric_generics_in_type(typ: &Type, found: &mut BTreeMap) { - match typ { - Type::FieldElement - | Type::Integer(_, _) - | Type::Bool - | Type::Unit - | Type::Error - | Type::TypeVariable(_, _) - | Type::Constant(_) - | Type::NamedGeneric(_, _) - | Type::Code - | Type::Forall(_, _) => (), - - Type::TraitAsType(_, _, args) => { - for arg in args { - Self::find_numeric_generics_in_type(arg, found); - } - } - - Type::Array(length, element_type) => { - if let Type::NamedGeneric(type_variable, name) = length.as_ref() { - found.insert(name.to_string(), type_variable.clone()); - } - Self::find_numeric_generics_in_type(element_type, found); - } - - Type::Slice(element_type) => { - Self::find_numeric_generics_in_type(element_type, found); - } - - Type::Tuple(fields) => { - for field in fields { - Self::find_numeric_generics_in_type(field, found); - } - } - - Type::Function(parameters, return_type, _env) => { - for parameter in parameters { - Self::find_numeric_generics_in_type(parameter, found); - } - Self::find_numeric_generics_in_type(return_type, found); - } - - Type::Struct(struct_type, generics) => { - for (i, generic) in generics.iter().enumerate() { - if let Type::NamedGeneric(type_variable, name) = generic { - if struct_type.borrow().generic_is_numeric(i) { - found.insert(name.to_string(), type_variable.clone()); - } - } else { - Self::find_numeric_generics_in_type(generic, found); - } - } - } - Type::Alias(alias, generics) => { - for (i, generic) in generics.iter().enumerate() { - if let Type::NamedGeneric(type_variable, name) = generic { - if alias.borrow().generic_is_numeric(i) { - found.insert(name.to_string(), type_variable.clone()); - } - } else { - Self::find_numeric_generics_in_type(generic, found); - } - } - } - Type::MutableReference(element) => Self::find_numeric_generics_in_type(element, found), - Type::String(length) => { - if let Type::NamedGeneric(type_variable, name) = length.as_ref() { - found.insert(name.to_string(), type_variable.clone()); - } - } - Type::FmtString(length, fields) => { - if let Type::NamedGeneric(type_variable, name) = length.as_ref() { - found.insert(name.to_string(), type_variable.clone()); - } - Self::find_numeric_generics_in_type(fields, found); - } - } - } - fn add_trait_constraints_to_scope(&mut self, func_meta: &FuncMeta) { for constraint in &func_meta.trait_constraints { let object = constraint.typ.clone(); diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 955b4af327..d901e08463 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::{rc::Rc, collections::BTreeMap}; use acvm::acir::AcirField; use iter_extended::vecmap; @@ -22,7 +22,7 @@ use crate::{ HirBinaryOp, HirCallExpression, HirIdent, HirMemberAccess, HirMethodReference, HirPrefixExpression, }, - function::FuncMeta, + function::{FuncMeta, Parameters}, traits::TraitConstraint, }, macros_api::{ @@ -1424,4 +1424,96 @@ impl<'context> Elaborator<'context> { self.generics.push((rc_name, typevar, span)); } } + + pub fn find_numeric_generics( + parameters: &Parameters, + return_type: &Type, + ) -> Vec<(String, TypeVariable)> { + let mut found = BTreeMap::new(); + for (_, parameter, _) in ¶meters.0 { + Self::find_numeric_generics_in_type(parameter, &mut found); + } + Self::find_numeric_generics_in_type(return_type, &mut found); + found.into_iter().collect() + } + + fn find_numeric_generics_in_type(typ: &Type, found: &mut BTreeMap) { + match typ { + Type::FieldElement + | Type::Integer(_, _) + | Type::Bool + | Type::Unit + | Type::Error + | Type::TypeVariable(_, _) + | Type::Constant(_) + | Type::NamedGeneric(_, _) + | Type::Code + | Type::Forall(_, _) => (), + + Type::TraitAsType(_, _, args) => { + for arg in args { + Self::find_numeric_generics_in_type(arg, found); + } + } + + Type::Array(length, element_type) => { + if let Type::NamedGeneric(type_variable, name) = length.as_ref() { + found.insert(name.to_string(), type_variable.clone()); + } + Self::find_numeric_generics_in_type(element_type, found); + } + + Type::Slice(element_type) => { + Self::find_numeric_generics_in_type(element_type, found); + } + + Type::Tuple(fields) => { + for field in fields { + Self::find_numeric_generics_in_type(field, found); + } + } + + Type::Function(parameters, return_type, _env) => { + for parameter in parameters { + Self::find_numeric_generics_in_type(parameter, found); + } + Self::find_numeric_generics_in_type(return_type, found); + } + + Type::Struct(struct_type, generics) => { + for (i, generic) in generics.iter().enumerate() { + if let Type::NamedGeneric(type_variable, name) = generic { + if struct_type.borrow().generic_is_numeric(i) { + found.insert(name.to_string(), type_variable.clone()); + } + } else { + Self::find_numeric_generics_in_type(generic, found); + } + } + } + Type::Alias(alias, generics) => { + for (i, generic) in generics.iter().enumerate() { + if let Type::NamedGeneric(type_variable, name) = generic { + if alias.borrow().generic_is_numeric(i) { + found.insert(name.to_string(), type_variable.clone()); + } + } else { + Self::find_numeric_generics_in_type(generic, found); + } + } + } + Type::MutableReference(element) => Self::find_numeric_generics_in_type(element, found), + Type::String(length) => { + if let Type::NamedGeneric(type_variable, name) = length.as_ref() { + found.insert(name.to_string(), type_variable.clone()); + } + } + Type::FmtString(length, fields) => { + if let Type::NamedGeneric(type_variable, name) = length.as_ref() { + found.insert(name.to_string(), type_variable.clone()); + } + Self::find_numeric_generics_in_type(fields, found); + } + } + } } diff --git a/compiler/noirc_frontend/src/hir/comptime/scan.rs b/compiler/noirc_frontend/src/hir/comptime/scan.rs index cb2e95fdce..9ae2febb82 100644 --- a/compiler/noirc_frontend/src/hir/comptime/scan.rs +++ b/compiler/noirc_frontend/src/hir/comptime/scan.rs @@ -79,7 +79,14 @@ impl<'interner> Interpreter<'interner> { HirExpression::If(if_) => self.scan_if(if_), HirExpression::Tuple(tuple) => self.scan_tuple(tuple), HirExpression::Lambda(lambda) => self.scan_lambda(lambda), - HirExpression::Comptime(_block) => Ok(()), + HirExpression::Comptime(block) => { + let location = self.interner.expr_location(&expr); + let new_expr = + self.evaluate_block(block)?.into_hir_expression(self.interner, location)?; + let new_expr = self.interner.expression(&new_expr); + self.interner.replace_expr(&expr, new_expr); + Ok(()) + }, HirExpression::Quote(_) => { // This error could be detected much earlier in the compiler pipeline but // it just makes sense for the comptime code to handle comptime things. @@ -220,7 +227,13 @@ impl<'interner> Interpreter<'interner> { HirStatement::Expression(expression) => self.scan_expression(expression), HirStatement::Semi(semi) => self.scan_expression(semi), HirStatement::Error => Ok(()), - HirStatement::Comptime(_) => Ok(()), + HirStatement::Comptime(comptime) => { + let location = self.interner.statement_location(comptime); + let new_expr = + self.evaluate_comptime(comptime)?.into_hir_expression(self.interner, location)?; + self.interner.replace_statement(statement, HirStatement::Expression(new_expr)); + Ok(()) + }, } } @@ -234,7 +247,11 @@ impl<'interner> Interpreter<'interner> { Ok(()) } - fn inline_expression(&mut self, _value: Value, _expr: ExprId) -> IResult<()> { + fn inline_expression(&mut self, value: Value, expr: ExprId) -> IResult<()> { + let location = self.interner.expr_location(&expr); + let new_expr = value.into_hir_expression(self.interner, location)?; + let new_expr = self.interner.expression(&new_expr); + self.interner.replace_expr(&expr, new_expr); Ok(()) } } diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 92ba99d334..44b1e7b842 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -9,9 +9,9 @@ use crate::{ ast::{ ArrayLiteral, BlockExpression, ConstructorExpression, Ident, IntegerBitSize, Signedness, }, - hir_def::expr::{HirIdent, HirLambda, ImplKind}, - macros_api::{Expression, ExpressionKind, HirExpression, Literal, NodeInterner, Path}, - node_interner::FuncId, + hir_def::expr::{HirIdent, HirLambda, ImplKind, HirConstructorExpression, HirArrayLiteral}, + macros_api::{Expression, ExpressionKind, HirExpression, Literal, NodeInterner, Path, HirLiteral}, + node_interner::{FuncId, ExprId}, Shared, Type, }; use rustc_hash::FxHashMap as HashMap; @@ -177,6 +177,107 @@ impl Value { Ok(Expression::new(kind, location.span)) } + + pub(crate) fn into_hir_expression( + self, + interner: &mut NodeInterner, + location: Location, + ) -> IResult { + let typ = self.get_type().into_owned(); + + let expression = match self { + Value::Unit => HirExpression::Literal(HirLiteral::Unit), + Value::Bool(value) => HirExpression::Literal(HirLiteral::Bool(value)), + Value::Field(value) => HirExpression::Literal(HirLiteral::Integer(value, false)), + Value::I8(value) => { + let negative = value < 0; + let value = value.abs(); + let value = (value as u128).into(); + HirExpression::Literal(HirLiteral::Integer(value, negative)) + } + Value::I16(value) => { + let negative = value < 0; + let value = value.abs(); + let value = (value as u128).into(); + HirExpression::Literal(HirLiteral::Integer(value, negative)) + } + Value::I32(value) => { + let negative = value < 0; + let value = value.abs(); + let value = (value as u128).into(); + HirExpression::Literal(HirLiteral::Integer(value, negative)) + } + Value::I64(value) => { + let negative = value < 0; + let value = value.abs(); + let value = (value as u128).into(); + HirExpression::Literal(HirLiteral::Integer(value, negative)) + } + Value::U8(value) => { + HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + } + Value::U16(value) => { + HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + } + Value::U32(value) => { + HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + } + Value::U64(value) => { + HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + } + Value::String(value) => HirExpression::Literal(HirLiteral::Str(unwrap_rc(value))), + Value::Function(id, _typ) => { + let id = interner.function_definition_id(id); + let impl_kind = ImplKind::NotATraitMethod; + HirExpression::Ident(HirIdent { location, id, impl_kind }, None) + } + Value::Closure(_lambda, _env, _typ) => { + // TODO: How should a closure's environment be inlined? + let item = "Returning closures from a comptime fn"; + return Err(InterpreterError::Unimplemented { item, location }); + } + Value::Tuple(fields) => { + let fields = try_vecmap(fields, |field| field.into_hir_expression(interner, location))?; + HirExpression::Tuple(fields) + } + Value::Struct(fields, typ) => { + let fields = try_vecmap(fields, |(name, field)| { + let field = field.into_hir_expression(interner, location)?; + Ok((Ident::new(unwrap_rc(name), location.span), field)) + })?; + + let (r#type, struct_generics) = match typ.follow_bindings() { + Type::Struct(def, generics) => (def, generics), + _ => return Err(InterpreterError::NonStructInConstructor { typ, location }), + }; + + HirExpression::Constructor(HirConstructorExpression { + r#type, + struct_generics, + fields, + }) + } + Value::Array(elements, _) => { + let elements = + try_vecmap(elements, |elements| elements.into_hir_expression(interner, location))?; + HirExpression::Literal(HirLiteral::Array(HirArrayLiteral::Standard(elements))) + } + Value::Slice(elements, _) => { + let elements = + try_vecmap(elements, |elements| elements.into_hir_expression(interner, location))?; + HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements))) + } + Value::Code(block) => HirExpression::Unquote(unwrap_rc(block)), + Value::Pointer(_) => { + return Err(InterpreterError::CannotInlineMacro { value: self, location }) + } + }; + + let id = interner.push_expr(expression); + interner.push_expr_location(id, location.span, location.file); + interner.push_expr_type(id, typ); + Ok(id) + } } /// Unwraps an Rc value without cloning the inner value if the reference count is 1. Clones otherwise. From f77bef5a3047caed247e41b8f73927a9d7a2ace8 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 13:50:32 +0100 Subject: [PATCH 05/24] fmt --- compiler/noirc_frontend/src/elaborator/mod.rs | 6 ++++-- .../noirc_frontend/src/elaborator/types.rs | 2 +- .../noirc_frontend/src/hir/comptime/scan.rs | 9 ++++---- .../noirc_frontend/src/hir/comptime/value.rs | 21 ++++++++++++------- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 1d1c567123..9906d25ad1 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -1151,11 +1151,13 @@ impl<'context> Elaborator<'context> { self.elaborate_global_let(let_stmt, global_id); if comptime { - let let_statement = self.interner.get_global_let_statement(global_id) + let let_statement = self + .interner + .get_global_let_statement(global_id) .expect("Let statement of global should be set by elaborate_global_let"); let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); - + if let Err(error) = interpreter.evaluate_let(let_statement) { self.errors.push(error.into_compilation_error_pair()); } diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index d901e08463..ed77ac5d17 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -1,4 +1,4 @@ -use std::{rc::Rc, collections::BTreeMap}; +use std::{collections::BTreeMap, rc::Rc}; use acvm::acir::AcirField; use iter_extended::vecmap; diff --git a/compiler/noirc_frontend/src/hir/comptime/scan.rs b/compiler/noirc_frontend/src/hir/comptime/scan.rs index 9ae2febb82..02010b6886 100644 --- a/compiler/noirc_frontend/src/hir/comptime/scan.rs +++ b/compiler/noirc_frontend/src/hir/comptime/scan.rs @@ -86,7 +86,7 @@ impl<'interner> Interpreter<'interner> { let new_expr = self.interner.expression(&new_expr); self.interner.replace_expr(&expr, new_expr); Ok(()) - }, + } HirExpression::Quote(_) => { // This error could be detected much earlier in the compiler pipeline but // it just makes sense for the comptime code to handle comptime things. @@ -229,11 +229,12 @@ impl<'interner> Interpreter<'interner> { HirStatement::Error => Ok(()), HirStatement::Comptime(comptime) => { let location = self.interner.statement_location(comptime); - let new_expr = - self.evaluate_comptime(comptime)?.into_hir_expression(self.interner, location)?; + let new_expr = self + .evaluate_comptime(comptime)? + .into_hir_expression(self.interner, location)?; self.interner.replace_statement(statement, HirStatement::Expression(new_expr)); Ok(()) - }, + } } } diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 44b1e7b842..fd6d8a2db9 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -9,9 +9,11 @@ use crate::{ ast::{ ArrayLiteral, BlockExpression, ConstructorExpression, Ident, IntegerBitSize, Signedness, }, - hir_def::expr::{HirIdent, HirLambda, ImplKind, HirConstructorExpression, HirArrayLiteral}, - macros_api::{Expression, ExpressionKind, HirExpression, Literal, NodeInterner, Path, HirLiteral}, - node_interner::{FuncId, ExprId}, + hir_def::expr::{HirArrayLiteral, HirConstructorExpression, HirIdent, HirLambda, ImplKind}, + macros_api::{ + Expression, ExpressionKind, HirExpression, HirLiteral, Literal, NodeInterner, Path, + }, + node_interner::{ExprId, FuncId}, Shared, Type, }; use rustc_hash::FxHashMap as HashMap; @@ -237,7 +239,8 @@ impl Value { return Err(InterpreterError::Unimplemented { item, location }); } Value::Tuple(fields) => { - let fields = try_vecmap(fields, |field| field.into_hir_expression(interner, location))?; + let fields = + try_vecmap(fields, |field| field.into_hir_expression(interner, location))?; HirExpression::Tuple(fields) } Value::Struct(fields, typ) => { @@ -258,13 +261,15 @@ impl Value { }) } Value::Array(elements, _) => { - let elements = - try_vecmap(elements, |elements| elements.into_hir_expression(interner, location))?; + let elements = try_vecmap(elements, |elements| { + elements.into_hir_expression(interner, location) + })?; HirExpression::Literal(HirLiteral::Array(HirArrayLiteral::Standard(elements))) } Value::Slice(elements, _) => { - let elements = - try_vecmap(elements, |elements| elements.into_hir_expression(interner, location))?; + let elements = try_vecmap(elements, |elements| { + elements.into_hir_expression(interner, location) + })?; HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements))) } Value::Code(block) => HirExpression::Unquote(unwrap_rc(block)), From 4cd8b1fc9b11e257a28f32431cd33ff3716a3c7b Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 13:51:34 +0100 Subject: [PATCH 06/24] Add elaborator to CI --- tooling/nargo_cli/build.rs | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tooling/nargo_cli/build.rs b/tooling/nargo_cli/build.rs index 53c3966cb4..899e80b333 100644 --- a/tooling/nargo_cli/build.rs +++ b/tooling/nargo_cli/build.rs @@ -92,6 +92,17 @@ fn execution_success_{test_name}() {{ cmd.assert().success(); }} +#[test] +fn execution_success_elaborator_{test_name}() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("execute").arg("--force").arg("--use-elaborator"); + + cmd.assert().success(); +}} + #[test]{brillig_ignored} fn execution_success_{test_name}_brillig() {{ let test_program_dir = PathBuf::from("{test_dir}"); @@ -137,6 +148,17 @@ fn execution_failure_{test_name}() {{ cmd.arg("--program-dir").arg(test_program_dir); cmd.arg("execute").arg("--force"); + cmd.assert().failure().stderr(predicate::str::contains("The application panicked (crashed).").not()); +}} + +#[test] +fn execution_failure_elaborator_{test_name}() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("execute").arg("--force").arg("--use-elaborator"); + cmd.assert().failure().stderr(predicate::str::contains("The application panicked (crashed).").not()); }} "#, @@ -174,6 +196,17 @@ fn noir_test_success_{test_name}() {{ cmd.arg("--program-dir").arg(test_program_dir); cmd.arg("test"); + cmd.assert().success(); +}} + +#[test] +fn noir_test_success_elaborator_{test_name}() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("test").arg("--use-elaborator"); + cmd.assert().success(); }} "#, @@ -211,6 +244,17 @@ fn noir_test_failure_{test_name}() {{ cmd.arg("--program-dir").arg(test_program_dir); cmd.arg("test"); + cmd.assert().failure(); +}} + +#[test] +fn noir_test_failure_elaborator_{test_name}() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("test").arg("--use-elaborator"); + cmd.assert().failure(); }} "#, @@ -259,6 +303,34 @@ fn compile_success_empty_{test_name}() {{ panic!("`nargo info` failed with: {{}}", String::from_utf8(output.stderr).unwrap_or_default()); }} + // `compile_success_empty` tests should be able to compile down to an empty circuit. + let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap_or_else(|e| {{ + panic!("JSON was not well-formatted {{:?}}\n\n{{:?}}", e, std::str::from_utf8(&output.stdout)) + }}); + let num_opcodes = &json["programs"][0]["functions"][0]["acir_opcodes"]; + assert_eq!(num_opcodes.as_u64().expect("number of opcodes should fit in a u64"), 0); +}} + +#[test] +fn compile_success_empty_elaborator_{test_name}() {{ + + // We use a mocked backend for this test as we do not rely on the returned circuit size + // but we must call a backend as part of querying the number of opcodes in the circuit. + + let test_program_dir = PathBuf::from("{test_dir}"); + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("info"); + cmd.arg("--json"); + cmd.arg("--force"); + cmd.arg("--use-elaborator"); + + let output = cmd.output().expect("Failed to execute command"); + + if !output.status.success() {{ + panic!("`nargo info` failed with: {{}}", String::from_utf8(output.stderr).unwrap_or_default()); + }} + // `compile_success_empty` tests should be able to compile down to an empty circuit. let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap_or_else(|e| {{ panic!("JSON was not well-formatted {{:?}}\n\n{{:?}}", e, std::str::from_utf8(&output.stdout)) @@ -301,6 +373,16 @@ fn compile_success_contract_{test_name}() {{ cmd.arg("--program-dir").arg(test_program_dir); cmd.arg("compile").arg("--force"); + cmd.assert().success(); +}} +#[test] +fn compile_success_contract_elaborator_{test_name}() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("compile").arg("--force").arg("--use-elaborator"); + cmd.assert().success(); }} "#, @@ -338,6 +420,16 @@ fn compile_failure_{test_name}() {{ cmd.arg("--program-dir").arg(test_program_dir); cmd.arg("compile").arg("--force"); + cmd.assert().failure().stderr(predicate::str::contains("The application panicked (crashed).").not()); +}} +#[test] +fn compile_failure_elaborator_{test_name}() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("compile").arg("--force").arg("--use-elaborator"); + cmd.assert().failure().stderr(predicate::str::contains("The application panicked (crashed).").not()); }} "#, From 88514b39fbfe5d9e889e4860f9127ce72eb7f651 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 13:52:46 +0100 Subject: [PATCH 07/24] Fix frontend test --- compiler/noirc_frontend/src/hir/comptime/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/tests.rs b/compiler/noirc_frontend/src/hir/comptime/tests.rs index 41475d3ccf..17c1c8da73 100644 --- a/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -9,7 +9,8 @@ use crate::hir::type_check::test::type_check_src_code; fn interpret_helper(src: &str, func_namespace: Vec) -> Result { let (mut interner, main_id) = type_check_src_code(src, func_namespace); - let mut interpreter = Interpreter::new(&mut interner); + let mut scopes = vec![Default::default()]; + let mut interpreter = Interpreter::new(&mut interner, &mut scopes); let no_location = Location::dummy(); interpreter.call_function(main_id, Vec::new(), no_location) From 58a7d1089ab424c3441329a7a723a77548fa6027 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 13:55:21 +0100 Subject: [PATCH 08/24] Switch over frontend tests as well --- compiler/noirc_frontend/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 99215c8f17..93182264ad 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -81,7 +81,7 @@ pub(crate) fn get_program(src: &str) -> (ParsedModule, Context, Vec<(Compilation &mut context, program.clone().into_sorted(), root_file_id, - false, + true, &[], // No macro processors )); } From 5134c91584e5e1420723ac4363d48155b21f3584 Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 4 Jun 2024 15:02:45 +0100 Subject: [PATCH 09/24] Update compiler/noirc_frontend/src/ast/expression.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/ast/expression.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index 05188950d3..749e41d9c1 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -37,7 +37,7 @@ pub enum ExpressionKind { Comptime(BlockExpression), // This variant is only emitted when inlining the result of comptime - // code. It is used to translate function values back into the ast while + // code. It is used to translate function values back into the AST while // guaranteeing they have the same instantiated type and definition id without resolving again. Resolved(ExprId), Error, From ce25c87b054137368a159acd2de1235a1ab12f57 Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 4 Jun 2024 15:02:55 +0100 Subject: [PATCH 10/24] Update compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index ecbb7f985d..096bab2b47 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -548,7 +548,7 @@ impl ResolvedModule { /// Evaluate all `comptime` expressions in this module fn evaluate_comptime(&mut self, interner: &mut NodeInterner) { if self.count_errors() == 0 { - let mut scopes = vec![Default::default()]; + let mut scopes = vec![HashMap::default()]; let mut interpreter = Interpreter::new(interner, &mut scopes); for (_file, global) in &self.globals { From 001b0b09029ab4d4ceba48e02ec9a93a8659c149 Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 4 Jun 2024 15:03:08 +0100 Subject: [PATCH 11/24] Update compiler/noirc_frontend/src/hir/comptime/value.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/comptime/value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index fd6d8a2db9..363d4db836 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -267,8 +267,8 @@ impl Value { HirExpression::Literal(HirLiteral::Array(HirArrayLiteral::Standard(elements))) } Value::Slice(elements, _) => { - let elements = try_vecmap(elements, |elements| { - elements.into_hir_expression(interner, location) + let elements = try_vecmap(elements, |element| { + element.into_hir_expression(interner, location) })?; HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements))) } From 1fc373401bc4146d7f14d90c6860eb87aa7b3fd8 Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 4 Jun 2024 15:03:15 +0100 Subject: [PATCH 12/24] Update compiler/noirc_frontend/src/hir/comptime/value.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/comptime/value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 363d4db836..b2bff826a7 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -261,8 +261,8 @@ impl Value { }) } Value::Array(elements, _) => { - let elements = try_vecmap(elements, |elements| { - elements.into_hir_expression(interner, location) + let elements = try_vecmap(elements, |element| { + element.into_hir_expression(interner, location) })?; HirExpression::Literal(HirLiteral::Array(HirArrayLiteral::Standard(elements))) } From c025ba8d668ea980258d487fa5e2a57d1773bfad Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 4 Jun 2024 15:04:04 +0100 Subject: [PATCH 13/24] Update compiler/noirc_frontend/src/hir/comptime/value.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/comptime/value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index b2bff826a7..b0eed5e1ff 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -163,7 +163,7 @@ impl Value { } Value::Array(elements, _) => { let elements = - try_vecmap(elements, |elements| elements.into_expression(interner, location))?; + try_vecmap(elements, |element| element.into_expression(interner, location))?; ExpressionKind::Literal(Literal::Array(ArrayLiteral::Standard(elements))) } Value::Slice(elements, _) => { From c70c8464fa377ec8f41220595e749c8ff67fbddf Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 4 Jun 2024 15:04:12 +0100 Subject: [PATCH 14/24] Update compiler/noirc_frontend/src/hir/comptime/value.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/comptime/value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index b0eed5e1ff..f2ff93b892 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -168,7 +168,7 @@ impl Value { } Value::Slice(elements, _) => { let elements = - try_vecmap(elements, |elements| elements.into_expression(interner, location))?; + try_vecmap(elements, |element| element.into_expression(interner, location))?; ExpressionKind::Literal(Literal::Slice(ArrayLiteral::Standard(elements))) } Value::Code(block) => ExpressionKind::Block(unwrap_rc(block)), From ff011ef997c1d52391aaf0f6b6a22d141c2e9456 Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 4 Jun 2024 15:04:23 +0100 Subject: [PATCH 15/24] Update compiler/noirc_frontend/src/hir/comptime/tests.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/comptime/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/tests.rs b/compiler/noirc_frontend/src/hir/comptime/tests.rs index 17c1c8da73..8a7ef49613 100644 --- a/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -9,7 +9,7 @@ use crate::hir::type_check::test::type_check_src_code; fn interpret_helper(src: &str, func_namespace: Vec) -> Result { let (mut interner, main_id) = type_check_src_code(src, func_namespace); - let mut scopes = vec![Default::default()]; + let mut scopes = vec![HashMap::default()]; let mut interpreter = Interpreter::new(&mut interner, &mut scopes); let no_location = Location::dummy(); From efb3ddecc0b6cdb1b7b4508ab0b94fb636ed18e5 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 15:18:12 +0100 Subject: [PATCH 16/24] Inline comptime values in comptime statements --- .../src/elaborator/expressions.rs | 12 ++++++++-- .../src/elaborator/statements.rs | 22 ++++++------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index b98b1383cb..abd8781a21 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -9,7 +9,7 @@ use crate::{ UnresolvedTypeExpression, }, hir::{ - comptime::{Interpreter, InterpreterError}, + comptime::{self, Interpreter, InterpreterError}, resolution::{errors::ResolverError, resolver::LambdaContext}, type_check::TypeCheckError, }, @@ -634,7 +634,15 @@ impl<'context> Elaborator<'context> { fn elaborate_comptime_block(&mut self, block: BlockExpression, span: Span) -> (ExprId, Type) { let (block, _typ) = self.elaborate_block_expression(block); let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); + let value = interpreter.evaluate_block(block); + self.inline_comptime_value(value, span) + } + pub(super) fn inline_comptime_value( + &mut self, + value: Result, + span: Span, + ) -> (ExprId, Type) { let make_error = |this: &mut Self, error: InterpreterError| { this.errors.push(error.into_compilation_error_pair()); let error = this.interner.push_expr(HirExpression::Error); @@ -642,7 +650,7 @@ impl<'context> Elaborator<'context> { (error, Type::Error) }; - let value = match interpreter.evaluate_block(block) { + let value = match value { Ok(value) => value, Err(error) => return make_error(self, error), }; diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index c5cf6f1bc0..c965ef4539 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -14,8 +14,7 @@ use crate::{ }, }, macros_api::{ - ForLoopStatement, ForRange, HirExpression, HirLiteral, HirStatement, LetStatement, - Statement, StatementKind, + ForLoopStatement, ForRange, HirStatement, LetStatement, Statement, StatementKind, }, node_interner::{DefinitionId, DefinitionKind, GlobalId, StmtId}, Type, @@ -32,7 +31,7 @@ impl<'context> Elaborator<'context> { StatementKind::For(for_stmt) => self.elaborate_for(for_stmt), StatementKind::Break => self.elaborate_jump(true, statement.span), StatementKind::Continue => self.elaborate_jump(false, statement.span), - StatementKind::Comptime(statement) => self.elaborate_comptime(*statement), + StatementKind::Comptime(statement) => self.elaborate_comptime_statement(*statement), StatementKind::Expression(expr) => { let (expr, typ) = self.elaborate_expression(expr); (HirStatement::Expression(expr), typ) @@ -437,19 +436,12 @@ impl<'context> Elaborator<'context> { None } - pub(super) fn elaborate_comptime(&mut self, statement: Statement) -> (HirStatement, Type) { + fn elaborate_comptime_statement(&mut self, statement: Statement) -> (HirStatement, Type) { let span = statement.span; - let (hir_statement, typ) = self.elaborate_statement(statement); + let (hir_statement, _typ) = self.elaborate_statement(statement); let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); - - if let Err(error) = interpreter.evaluate_statement(hir_statement) { - self.errors.push(error.into_compilation_error_pair()); - } - - let unit = HirExpression::Literal(HirLiteral::Unit); - let unit = self.interner.push_expr(unit); - self.interner.push_expr_type(unit, Type::Unit); - self.interner.push_expr_location(unit, span, self.file); - (HirStatement::Expression(unit), typ) + let value = interpreter.evaluate_statement(hir_statement); + let (expr, typ) = self.inline_comptime_value(value, span); + (HirStatement::Expression(expr), typ) } } From ccf726fd0c28c6d6faf5525b3ef3296534781b85 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 16:04:44 +0100 Subject: [PATCH 17/24] Import hashmap --- compiler/noirc_frontend/src/hir/comptime/tests.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/tests.rs b/compiler/noirc_frontend/src/hir/comptime/tests.rs index 8a7ef49613..43f6e21905 100644 --- a/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -1,5 +1,7 @@ #![cfg(test)] +use std::collections::HashMap; + use noirc_errors::Location; use super::errors::InterpreterError; From c30f167b8eee3b674a00318d29ca5e4a55fa5d4b Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 16:48:37 +0100 Subject: [PATCH 18/24] Define functions lazily --- compiler/noirc_frontend/src/elaborator/mod.rs | 63 ++++++++++--------- .../noirc_frontend/src/elaborator/traits.rs | 5 +- .../noirc_frontend/src/elaborator/types.rs | 29 +++------ .../src/hir/resolution/resolver.rs | 4 +- .../noirc_frontend/src/hir_def/function.rs | 25 ++++++++ 5 files changed, 72 insertions(+), 54 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 9906d25ad1..a8ff91d706 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -18,9 +18,9 @@ use crate::{ scope::ScopeForest as GenericScopeForest, type_check::{check_trait_impl_method_matches_declaration, TypeCheckError}, }, - hir_def::{expr::HirIdent, function::Parameters, traits::TraitConstraint}, + hir_def::{expr::HirIdent, function::{Parameters, FunctionBody}, traits::TraitConstraint}, macros_api::{ - Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, SecondaryAttribute, StructId, + Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, SecondaryAttribute, StructId, BlockExpression, }, node_interner::{ DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, TraitId, TypeAliasId, @@ -136,7 +136,8 @@ pub struct Elaborator<'context> { /// ``` resolving_ids: BTreeSet, - trait_bounds: Vec, + /// Each constraint in the `where` clause of the function currently being resolved. + trait_bounds: Vec, current_function: Option, @@ -273,16 +274,28 @@ impl<'context> Elaborator<'context> { self.trait_id = functions.trait_id; // TODO: Resolve? self.self_type = functions.self_type; - for (local_module, id, func) in functions.functions { + for (local_module, id, _) in functions.functions { self.local_module = local_module; - self.recover_generics(|this| this.elaborate_function(func, id)); + self.recover_generics(|this| this.elaborate_function(id)); } self.self_type = None; self.trait_id = None; } - fn elaborate_function(&mut self, function: NoirFunction, id: FuncId) { + fn elaborate_function(&mut self, id: FuncId) { + let func_meta = self.interner.func_meta.get_mut(&id); + let func_meta = func_meta + .expect("FuncMetas should be declared before a function is elaborated"); + + let (kind, body, body_span) = match func_meta.take_body() { + FunctionBody::Unresolved(kind, body, span) => (kind, body, span), + FunctionBody::Resolved => return, + // Do not error for the still-resolving case. If there is a dependency cycle, + // the dependency cycle check will find it later on. + FunctionBody::Resolving => return, + }; + self.current_function = Some(id); // Without this, impl methods can accidentally be placed in contracts. See #3254 @@ -293,17 +306,14 @@ impl<'context> Elaborator<'context> { self.scopes.start_function(); self.current_item = Some(DependencyId::Function(id)); - self.trait_bounds = function.def.where_clause.clone(); + let func_meta = func_meta.clone(); + + self.trait_bounds = func_meta.trait_constraints.clone(); - if function.def.is_unconstrained { + if self.interner.function_modifiers(&id).is_unconstrained { self.in_unconstrained_fn = true; } - let func_meta = self.interner.func_meta.get(&id); - let func_meta = func_meta - .expect("FuncMetas should be declared before a function is elaborated") - .clone(); - // The DefinitionIds for each parameter were already created in define_function_meta // so we need to reintroduce the same IDs into scope here. for parameter in &func_meta.parameter_idents { @@ -315,14 +325,13 @@ impl<'context> Elaborator<'context> { self.declare_numeric_generics(&func_meta.parameters, func_meta.return_type()); self.add_trait_constraints_to_scope(&func_meta); - let (hir_func, body_type) = match function.kind { + let (hir_func, body_type) = match kind { FunctionKind::Builtin | FunctionKind::LowLevel | FunctionKind::Oracle => { (HirFunction::empty(), Type::Error) } FunctionKind::Normal | FunctionKind::Recursive => { - let block_span = function.def.span; - let (block, body_type) = self.elaborate_block(function.def.body); - let expr_id = self.intern_expr(block, block_span); + let (block, body_type) = self.elaborate_block(body); + let expr_id = self.intern_expr(block, body_span); self.interner.push_expr_type(expr_id, body_type.clone()); (HirFunction::unchecked_from_expr(expr_id), body_type) } @@ -374,8 +383,12 @@ impl<'context> Elaborator<'context> { self.check_for_unused_variables_in_scope_tree(func_scope_tree); } - self.trait_bounds.clear(); + let meta = self.interner.func_meta.get_mut(&id) + .expect("FuncMetas should be declared before a function is elaborated"); + + meta.function_body = FunctionBody::Resolved; + self.trait_bounds.clear(); self.interner.update_fn(id, hir_func); self.current_function = None; } @@ -438,15 +451,6 @@ impl<'context> Elaborator<'context> { self.errors.push((error.into(), self.file)); } - fn resolve_where_clause(&mut self, clause: &mut [UnresolvedTraitConstraint]) { - for bound in clause { - if let Some(trait_id) = self.resolve_trait_by_path(bound.trait_bound.trait_path.clone()) - { - bound.trait_bound.trait_id = Some(trait_id); - } - } - } - fn resolve_trait_by_path(&mut self, path: Path) -> Option { let path_resolver = StandardPathResolver::new(self.module_id()); @@ -518,7 +522,6 @@ impl<'context> Elaborator<'context> { is_trait_function: bool, ) { self.current_function = Some(func_id); - self.resolve_where_clause(&mut func.def.where_clause); // Without this, impl methods can accidentally be placed in contracts. See #3254 if self.self_type.is_some() { @@ -649,6 +652,9 @@ impl<'context> Elaborator<'context> { .map(|(name, typevar, _span)| (name.clone(), typevar.clone())) .collect(); + let statements = std::mem::take(&mut func.def.body.statements); + let body = BlockExpression { statements }; + let meta = FuncMeta { name: name_ident, kind: func.kind, @@ -666,6 +672,7 @@ impl<'context> Elaborator<'context> { is_entry_point, is_trait_function, has_inline_attribute, + function_body: FunctionBody::Unresolved(func.kind, body, func.def.span), }; self.interner.push_fn_meta(meta, func_id); diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index 30a6f50ad5..3e04dbc784 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -149,8 +149,6 @@ impl<'context> Elaborator<'context> { let old_generic_count = self.generics.len(); self.scopes.start_function(); - self.trait_bounds = where_clause.to_vec(); - let kind = FunctionKind::Normal; let def = FunctionDefinition { name: name.clone(), @@ -174,10 +172,9 @@ impl<'context> Elaborator<'context> { let mut function = NoirFunction { kind, def }; self.define_function_meta(&mut function, func_id, true); - self.elaborate_function(function, func_id); + self.elaborate_function(func_id); let _ = self.scopes.end_function(); // Don't check the scope tree for unused variables, they can't be used in a declaration anyway. - self.trait_bounds.clear(); self.generics.truncate(old_generic_count); } } diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index ed77ac5d17..4bbc9b8348 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -6,7 +6,7 @@ use noirc_errors::{Location, Span}; use crate::{ ast::{ - BinaryOpKind, IntegerBitSize, UnresolvedGenerics, UnresolvedTraitConstraint, + BinaryOpKind, IntegerBitSize, UnresolvedGenerics, UnresolvedTypeExpression, }, hir::{ @@ -370,31 +370,18 @@ impl<'context> Elaborator<'context> { return None; } - for UnresolvedTraitConstraint { typ, trait_bound } in self.trait_bounds.clone() { - if let UnresolvedTypeData::Named(constraint_path, _, _) = &typ.typ { + for constraint in self.trait_bounds.clone() { + if let Type::NamedGeneric(_, name) = &constraint.typ { // if `path` is `T::method_name`, we're looking for constraint of the form `T: SomeTrait` - if constraint_path.segments.len() == 1 - && path.segments[0] != constraint_path.last_segment() - { + if path.segments[0].0.contents != name.as_str() { continue; } - if let Ok(ModuleDefId::TraitId(trait_id)) = - self.resolve_path(trait_bound.trait_path.clone()) + let the_trait = self.interner.get_trait(constraint.trait_id); + if let Some(method) = + the_trait.find_method(path.segments.last().unwrap().0.contents.as_str()) { - let the_trait = self.interner.get_trait(trait_id); - if let Some(method) = - the_trait.find_method(path.segments.last().unwrap().0.contents.as_str()) - { - let constraint = TraitConstraint { - trait_id, - typ: self.resolve_type(typ.clone()), - trait_generics: vecmap(trait_bound.trait_generics, |typ| { - self.resolve_type(typ) - }), - }; - return Some((method, constraint, true)); - } + return Some((method, constraint, true)); } } } diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 8f5e99bacb..2eed71addc 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -20,6 +20,7 @@ use crate::hir_def::expr::{ HirMethodCallExpression, HirPrefixExpression, ImplKind, }; +use crate::hir_def::function::FunctionBody; use crate::hir_def::traits::{Trait, TraitConstraint}; use crate::macros_api::SecondaryAttribute; use crate::token::{Attributes, FunctionAttribute}; @@ -1074,10 +1075,11 @@ impl<'a> Resolver<'a> { is_entry_point: self.is_entry_point_function(func), has_inline_attribute, - // This is only used by the elaborator + // These fields are only used by the elaborator all_generics: Vec::new(), is_trait_function: false, parameter_idents: Vec::new(), + function_body: FunctionBody::Resolved, } } diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index 3bd85e94dc..0a40720122 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -7,6 +7,7 @@ use super::expr::{HirBlockExpression, HirExpression, HirIdent}; use super::stmt::HirPattern; use super::traits::TraitConstraint; use crate::ast::{FunctionKind, FunctionReturnType, Visibility}; +use crate::macros_api::BlockExpression; use crate::node_interner::{ExprId, NodeInterner, TraitImplId}; use crate::{Type, TypeVariable}; @@ -142,6 +143,15 @@ pub struct FuncMeta { /// that indicates it should be inlined differently than the default (inline everything). /// For example, such as `fold` (never inlined) or `no_predicates` (inlined after flattening) pub has_inline_attribute: bool, + + pub function_body: FunctionBody, +} + +#[derive(Debug, Clone)] +pub enum FunctionBody { + Unresolved(FunctionKind, BlockExpression, Span), + Resolving, + Resolved, } impl FuncMeta { @@ -173,4 +183,19 @@ impl FuncMeta { _ => unreachable!(), } } + + /// Take this function body, returning an owned version while avoiding + /// cloning any large Expressions inside by replacing a Unresolved with a Resolving variant. + pub fn take_body(&mut self) -> FunctionBody { + match &mut self.function_body { + FunctionBody::Unresolved(kind, block, span) => { + let statements = std::mem::take(&mut block.statements); + let (kind, span) = (*kind, *span); + self.function_body = FunctionBody::Resolving; + FunctionBody::Unresolved(kind, BlockExpression { statements }, span) + }, + FunctionBody::Resolving => FunctionBody::Resolving, + FunctionBody::Resolved => FunctionBody::Resolved, + } + } } From e2b4b59647bc7faf4718e5e49c9896687d72e3bd Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 4 Jun 2024 18:33:39 +0100 Subject: [PATCH 19/24] Fix globals --- Cargo.lock | 1 - compiler/noirc_driver/Cargo.toml | 1 - compiler/noirc_driver/src/lib.rs | 20 ++++-- compiler/noirc_frontend/src/elaborator/mod.rs | 66 +++++++++++++------ .../noirc_frontend/src/elaborator/patterns.rs | 65 +++++++++++------- .../src/elaborator/statements.rs | 54 +++++++-------- .../noirc_frontend/src/elaborator/types.rs | 5 +- .../src/hir/comptime/interpreter.rs | 7 +- .../noirc_frontend/src/hir_def/function.rs | 2 +- .../src/monomorphization/errors.rs | 23 ++++--- .../src/monomorphization/mod.rs | 17 +++-- compiler/noirc_frontend/src/node_interner.rs | 7 ++ 12 files changed, 166 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b140a513f..61bfdd08c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2775,7 +2775,6 @@ dependencies = [ "noirc_frontend", "rust-embed", "serde", - "thiserror", "tracing", ] diff --git a/compiler/noirc_driver/Cargo.toml b/compiler/noirc_driver/Cargo.toml index 495410b7b0..a9949f5093 100644 --- a/compiler/noirc_driver/Cargo.toml +++ b/compiler/noirc_driver/Cargo.toml @@ -24,6 +24,5 @@ serde.workspace = true fxhash.workspace = true rust-embed.workspace = true tracing.workspace = true -thiserror.workspace = true aztec_macros = { path = "../../aztec_macros" } diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index d7368f299b..848d9987ca 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -24,7 +24,6 @@ use noirc_frontend::monomorphization::{ use noirc_frontend::node_interner::FuncId; use noirc_frontend::token::SecondaryAttribute; use std::path::Path; -use thiserror::Error; use tracing::info; mod abi_gen; @@ -117,13 +116,22 @@ fn parse_expression_width(input: &str) -> Result for CompileError { + fn from(error: MonomorphizationError) -> Self { + Self::MonomorphizationError(error) + } +} + +impl From for CompileError { + fn from(error: RuntimeError) -> Self { + Self::RuntimeError(error) + } } impl From for FileDiagnostic { diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index a8ff91d706..87e243297f 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -18,12 +18,17 @@ use crate::{ scope::ScopeForest as GenericScopeForest, type_check::{check_trait_impl_method_matches_declaration, TypeCheckError}, }, - hir_def::{expr::HirIdent, function::{Parameters, FunctionBody}, traits::TraitConstraint}, + hir_def::{ + expr::HirIdent, + function::{FunctionBody, Parameters}, + traits::TraitConstraint, + }, macros_api::{ - Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, SecondaryAttribute, StructId, BlockExpression, + BlockExpression, Ident, NodeInterner, NoirFunction, NoirStruct, Pattern, + SecondaryAttribute, StructId, }, node_interner::{ - DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, TraitId, TypeAliasId, + DefinitionId, DefinitionKind, DependencyId, ExprId, FuncId, GlobalId, TraitId, TypeAliasId, }, Shared, Type, TypeVariable, }; @@ -285,8 +290,8 @@ impl<'context> Elaborator<'context> { fn elaborate_function(&mut self, id: FuncId) { let func_meta = self.interner.func_meta.get_mut(&id); - let func_meta = func_meta - .expect("FuncMetas should be declared before a function is elaborated"); + let func_meta = + func_meta.expect("FuncMetas should be declared before a function is elaborated"); let (kind, body, body_span) = match func_meta.take_body() { FunctionBody::Unresolved(kind, body, span) => (kind, body, span), @@ -296,7 +301,7 @@ impl<'context> Elaborator<'context> { FunctionBody::Resolving => return, }; - self.current_function = Some(id); + let old_function = std::mem::replace(&mut self.current_function, Some(id)); // Without this, impl methods can accidentally be placed in contracts. See #3254 if self.self_type.is_some() { @@ -304,7 +309,7 @@ impl<'context> Elaborator<'context> { } self.scopes.start_function(); - self.current_item = Some(DependencyId::Function(id)); + let old_item = std::mem::replace(&mut self.current_item, Some(DependencyId::Function(id))); let func_meta = func_meta.clone(); @@ -383,14 +388,18 @@ impl<'context> Elaborator<'context> { self.check_for_unused_variables_in_scope_tree(func_scope_tree); } - let meta = self.interner.func_meta.get_mut(&id) + let meta = self + .interner + .func_meta + .get_mut(&id) .expect("FuncMetas should be declared before a function is elaborated"); meta.function_body = FunctionBody::Resolved; self.trait_bounds.clear(); self.interner.update_fn(id, hir_func); - self.current_function = None; + self.current_function = old_function; + self.current_item = old_item; } /// This turns function parameters of the form: @@ -592,6 +601,7 @@ impl<'context> Elaborator<'context> { typ.clone(), DefinitionKind::Local(None), &mut parameter_idents, + None, ); parameters.push((pattern, typ.clone(), visibility)); @@ -1155,19 +1165,12 @@ impl<'context> Elaborator<'context> { let comptime = let_stmt.comptime; - self.elaborate_global_let(let_stmt, global_id); + let (let_statement, _typ) = 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); if comptime { - let let_statement = self - .interner - .get_global_let_statement(global_id) - .expect("Let statement of global should be set by elaborate_global_let"); - - let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); - - if let Err(error) = interpreter.evaluate_let(let_statement) { - self.errors.push(error.into_compilation_error_pair()); - } + self.elaborate_comptime_global(global_id); } // Avoid defaulting the types of globals here since they may be used in any function. @@ -1176,6 +1179,29 @@ impl<'context> Elaborator<'context> { self.type_variables.clear(); } + fn elaborate_comptime_global(&mut self, global_id: GlobalId) { + let let_statement = self + .interner + .get_global_let_statement(global_id) + .expect("Let statement of global should be set by elaborate_global_let"); + + let global = self.interner.get_global(global_id); + let definition_id = global.definition_id; + let location = global.location; + + let mut interpreter = Interpreter::new(self.interner, &mut self.comptime_scopes); + + if let Err(error) = interpreter.evaluate_let(let_statement) { + self.errors.push(error.into_compilation_error_pair()); + } else { + let value = interpreter + .lookup_id(definition_id, location) + .expect("The global should be defined since evaluate_let did not error"); + + self.interner.get_global_mut(global_id).value = Some(value); + } + } + fn define_function_metas( &mut self, functions: &mut [UnresolvedFunctions], diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 12b0b7b5e6..411caeba7b 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -11,10 +11,11 @@ use crate::{ }, hir_def::{ expr::{HirIdent, ImplKind}, + function::FunctionBody, stmt::HirPattern, }, macros_api::{HirExpression, Ident, Path, Pattern}, - node_interner::{DefinitionId, DefinitionKind, ExprId, TraitImplKind}, + node_interner::{DefinitionId, DefinitionKind, DependencyId, ExprId, GlobalId, TraitImplKind}, Shared, StructType, Type, TypeBindings, }; @@ -27,7 +28,14 @@ impl<'context> Elaborator<'context> { expected_type: Type, definition_kind: DefinitionKind, ) -> HirPattern { - self.elaborate_pattern_mut(pattern, expected_type, definition_kind, None, &mut Vec::new()) + self.elaborate_pattern_mut( + pattern, + expected_type, + definition_kind, + None, + &mut Vec::new(), + None, + ) } /// Equivalent to `elaborate_pattern`, this version just also @@ -38,8 +46,16 @@ impl<'context> Elaborator<'context> { expected_type: Type, definition_kind: DefinitionKind, created_ids: &mut Vec, + global_id: Option, ) -> HirPattern { - self.elaborate_pattern_mut(pattern, expected_type, definition_kind, None, created_ids) + self.elaborate_pattern_mut( + pattern, + expected_type, + definition_kind, + None, + created_ids, + global_id, + ) } fn elaborate_pattern_mut( @@ -49,6 +65,7 @@ impl<'context> Elaborator<'context> { definition: DefinitionKind, mutable: Option, new_definitions: &mut Vec, + global_id: Option, ) -> HirPattern { match pattern { Pattern::Identifier(name) => { @@ -58,7 +75,14 @@ impl<'context> Elaborator<'context> { (Some(_), DefinitionKind::Local(_)) => DefinitionKind::Local(None), (_, other) => other, }; - let ident = self.add_variable_decl(name, mutable.is_some(), true, definition); + let ident = if let Some(global_id) = global_id { + // Globals don't need to be added to scope, they're already in the def_maps + let id = self.interner.get_global(global_id).definition_id; + let location = Location::new(name.span(), self.file); + HirIdent::non_trait_method(id, location) + } else { + self.add_variable_decl(name, mutable.is_some(), true, definition) + }; self.interner.push_definition_type(ident.id, expected_type); new_definitions.push(ident.clone()); HirPattern::Identifier(ident) @@ -74,6 +98,7 @@ impl<'context> Elaborator<'context> { definition, Some(span), new_definitions, + global_id, ); let location = Location::new(span, self.file); HirPattern::Mutable(Box::new(pattern), location) @@ -104,6 +129,7 @@ impl<'context> Elaborator<'context> { definition.clone(), mutable, new_definitions, + global_id, ) }); let location = Location::new(span, self.file); @@ -200,6 +226,7 @@ impl<'context> Elaborator<'context> { definition.clone(), mutable, new_definitions, + None, ); if unseen_fields.contains(&field) { @@ -300,7 +327,7 @@ impl<'context> Elaborator<'context> { let mut global_id = None; let global = self.interner.get_all_globals(); for global_info in global { - if global_info.ident == name && global_info.local_id == self.local_module { + if global_info.local_id == self.local_module && global_info.ident == name { global_id = Some(global_info.id); } } @@ -332,22 +359,6 @@ impl<'context> Elaborator<'context> { ident } - // Checks for a variable having been declared before. - // (Variable declaration and definition cannot be separate in Noir.) - // Once the variable has been found, intern and link `name` to this definition, - // returning (the ident, the IdentId of `name`) - // - // If a variable is not found, then an error is logged and a dummy id - // is returned, for better error reporting UX - pub(super) fn find_variable_or_default(&mut self, name: &Ident) -> (HirIdent, usize) { - self.use_variable(name).unwrap_or_else(|error| { - self.push_err(error); - let id = DefinitionId::dummy_id(); - let location = Location::new(name.span(), self.file); - (HirIdent::non_trait_method(id, location), 0) - }) - } - /// Lookup and use the specified variable. /// This will increment its use counter by one and return the variable if found. /// If the variable is not found, an error is returned. @@ -404,6 +415,16 @@ impl<'context> Elaborator<'context> { match self.interner.definition(hir_ident.id).kind { DefinitionKind::Function(id) => { if let Some(current_item) = self.current_item { + // Lazily evaluate functions found within globals if necessary. + // Otherwise if we later attempt to evaluate the global it will + // see an empty function body. + if matches!(current_item, DependencyId::Global(_)) { + let meta = self.interner.function_meta(&id); + + if matches!(&meta.function_body, FunctionBody::Unresolved(..)) { + self.elaborate_function(id); + } + } self.interner.add_function_dependency(current_item, id); } } @@ -555,7 +576,7 @@ impl<'context> Elaborator<'context> { } } - fn get_ident_from_path(&mut self, path: Path) -> (HirIdent, usize) { + pub fn get_ident_from_path(&mut self, path: Path) -> (HirIdent, usize) { let location = Location::new(path.span(), self.file); let error = match path.as_ident().map(|ident| self.use_variable(ident)) { diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index c965ef4539..e055741627 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -14,7 +14,7 @@ use crate::{ }, }, macros_api::{ - ForLoopStatement, ForRange, HirStatement, LetStatement, Statement, StatementKind, + ForLoopStatement, ForRange, HirStatement, LetStatement, Path, Statement, StatementKind, }, node_interner::{DefinitionId, DefinitionKind, GlobalId, StmtId}, Type, @@ -53,39 +53,27 @@ impl<'context> Elaborator<'context> { } pub(super) fn elaborate_local_let(&mut self, let_stmt: LetStatement) -> (HirStatement, Type) { - let (statement, typ, _) = self.elaborate_let(let_stmt); - (statement, typ) + self.elaborate_let(let_stmt, None) } - /// Elaborates a global let statement. Compared to the local version, this - /// version fixes up the result to use the given DefinitionId rather than - /// the fresh one defined by the let pattern. - pub(super) fn elaborate_global_let(&mut self, let_stmt: LetStatement, global_id: GlobalId) { - let (let_statement, _typ, new_ids) = self.elaborate_let(let_stmt); - let statement_id = self.interner.get_global(global_id).let_statement; - - // To apply the changes from the fresh id created in elaborate_let to this global - // we need to change the definition kind and update the type. - assert_eq!(new_ids.len(), 1, "Globals should only define 1 value"); - let new_id = new_ids[0].id; - - self.interner.definition_mut(new_id).kind = DefinitionKind::Global(global_id); - - let definition_id = self.interner.get_global(global_id).definition_id; - let definition_type = self.interner.definition_type(new_id); - self.interner.push_definition_type(definition_id, definition_type); - - self.interner.replace_statement(statement_id, let_statement); - } - - /// Elaborate a local or global let statement. In addition to the HirLetStatement and unit - /// type, this also returns each HirIdent defined by this let statement. - fn elaborate_let(&mut self, let_stmt: LetStatement) -> (HirStatement, Type, Vec) { + /// Elaborate a local or global let statement. + /// If this is a global let, the DefinitionId of the global is specified so that + /// elaborate_pattern can create a Global definition kind with the correct ID + /// instead of a local one with a fresh ID. + pub(super) fn elaborate_let( + &mut self, + let_stmt: LetStatement, + global_id: Option, + ) -> (HirStatement, Type) { let expr_span = let_stmt.expression.span; let (expression, expr_type) = self.elaborate_expression(let_stmt.expression); - let definition = DefinitionKind::Local(Some(expression)); let annotated_type = self.resolve_type(let_stmt.r#type); + let definition = match global_id { + None => DefinitionKind::Local(Some(expression)), + Some(id) => DefinitionKind::Global(id), + }; + // First check if the LHS is unspecified // If so, then we give it the same type as the expression let r#type = if annotated_type != Type::Error { @@ -106,18 +94,18 @@ impl<'context> Elaborator<'context> { expr_type }; - let mut created_ids = Vec::new(); let pattern = self.elaborate_pattern_and_store_ids( let_stmt.pattern, r#type.clone(), definition, - &mut created_ids, + &mut Vec::new(), + global_id, ); let attributes = let_stmt.attributes; let comptime = let_stmt.comptime; let let_ = HirLetStatement { pattern, r#type, expression, attributes, comptime }; - (HirStatement::Let(let_), Type::Unit, created_ids) + (HirStatement::Let(let_), Type::Unit) } pub(super) fn elaborate_constrain(&mut self, stmt: ConstrainStatement) -> (HirStatement, Type) { @@ -247,7 +235,9 @@ impl<'context> Elaborator<'context> { match lvalue { LValue::Ident(ident) => { let mut mutable = true; - let (ident, scope_index) = self.find_variable_or_default(&ident); + let span = ident.span(); + let path = Path::from_single(ident.0.contents, span); + let (ident, scope_index) = self.get_ident_from_path(path); self.resolve_local_variable(ident.clone(), scope_index); let typ = if ident.id == DefinitionId::dummy_id() { diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 4bbc9b8348..fa0dcd3000 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -5,10 +5,7 @@ use iter_extended::vecmap; use noirc_errors::{Location, Span}; use crate::{ - ast::{ - BinaryOpKind, IntegerBitSize, UnresolvedGenerics, - UnresolvedTypeExpression, - }, + ast::{BinaryOpKind, IntegerBitSize, UnresolvedGenerics, UnresolvedTypeExpression}, hir::{ def_map::ModuleDefId, resolution::{ diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 82e7d70141..2d9c0dd4f1 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -239,6 +239,11 @@ impl<'a> Interpreter<'a> { /// Mutate an existing variable, potentially from a prior scope fn mutate(&mut self, id: DefinitionId, argument: Value, location: Location) -> IResult<()> { + // If the id is a dummy, assume the error was already issued elsewhere + if id == DefinitionId::dummy_id() { + return Ok(()); + } + for scope in self.scopes.iter_mut().rev() { if let Entry::Occupied(mut entry) = scope.entry(id) { entry.insert(argument); @@ -253,7 +258,7 @@ impl<'a> Interpreter<'a> { self.lookup_id(ident.id, ident.location) } - fn lookup_id(&self, id: DefinitionId, location: Location) -> IResult { + pub fn lookup_id(&self, id: DefinitionId, location: Location) -> IResult { for scope in self.scopes.iter().rev() { if let Some(value) = scope.get(&id) { return Ok(value.clone()); diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index 0a40720122..53eabe2108 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -193,7 +193,7 @@ impl FuncMeta { let (kind, span) = (*kind, *span); self.function_body = FunctionBody::Resolving; FunctionBody::Unresolved(kind, BlockExpression { statements }, span) - }, + } FunctionBody::Resolving => FunctionBody::Resolving, FunctionBody::Resolved => FunctionBody::Resolved, } diff --git a/compiler/noirc_frontend/src/monomorphization/errors.rs b/compiler/noirc_frontend/src/monomorphization/errors.rs index 3011c26cff..2db570540d 100644 --- a/compiler/noirc_frontend/src/monomorphization/errors.rs +++ b/compiler/noirc_frontend/src/monomorphization/errors.rs @@ -1,14 +1,12 @@ -use thiserror::Error; - use noirc_errors::{CustomDiagnostic, FileDiagnostic, Location}; -#[derive(Debug, Error)] +use crate::hir::comptime::InterpreterError; + +#[derive(Debug)] pub enum MonomorphizationError { - #[error("Length of generic array could not be determined.")] UnknownArrayLength { location: Location }, - - #[error("Type annotations needed")] TypeAnnotationsNeeded { location: Location }, + InterpreterError(InterpreterError), } impl MonomorphizationError { @@ -16,6 +14,7 @@ impl MonomorphizationError { match self { MonomorphizationError::UnknownArrayLength { location } | MonomorphizationError::TypeAnnotationsNeeded { location } => *location, + MonomorphizationError::InterpreterError(error) => error.get_location(), } } } @@ -31,9 +30,15 @@ impl From for FileDiagnostic { impl MonomorphizationError { fn into_diagnostic(self) -> CustomDiagnostic { - let message = self.to_string(); - let location = self.location(); + let message = match self { + MonomorphizationError::UnknownArrayLength { .. } => { + "Length of generic array could not be determined." + } + MonomorphizationError::TypeAnnotationsNeeded { .. } => "Type annotations needed", + MonomorphizationError::InterpreterError(error) => return (&error).into(), + }; - CustomDiagnostic::simple_error(message, String::new(), location.span) + let location = self.location(); + CustomDiagnostic::simple_error(message.into(), String::new(), location.span) } } diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 2e74eb87e6..cf5490506f 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -877,12 +877,19 @@ impl<'interner> Monomorphizer<'interner> { } } DefinitionKind::Global(global_id) => { - let Some(let_) = self.interner.get_global_let_statement(*global_id) else { - unreachable!( - "Globals should have a corresponding let statement by monomorphization" - ) + let global = self.interner.get_global(*global_id); + + let expr = if let Some(value) = global.value.clone() { + value + .into_hir_expression(self.interner, global.location) + .map_err(MonomorphizationError::InterpreterError)? + } else { + let let_ = self.interner.get_global_let_statement(*global_id).expect( + "Globals should have a corresponding let statement by monomorphization", + ); + let_.expression }; - self.expr(let_.expression)? + self.expr(expr)? } DefinitionKind::Local(_) => match self.lookup_captured_expr(ident.id) { Some(expr) => expr, diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index e28a0a64ad..adf5aef9a1 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -13,6 +13,7 @@ use petgraph::prelude::NodeIndex as PetGraphIndex; use crate::ast::Ident; use crate::graph::CrateId; +use crate::hir::comptime; use crate::hir::def_collector::dc_crate::CompilationError; use crate::hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait, UnresolvedTypeAlias}; use crate::hir::def_map::{LocalModuleId, ModuleId}; @@ -466,6 +467,7 @@ pub struct GlobalInfo { pub local_id: LocalModuleId, pub location: Location, pub let_statement: StmtId, + pub value: Option, } impl Default for NodeInterner { @@ -681,6 +683,7 @@ impl NodeInterner { local_id, let_statement, location, + value: None, }); self.global_attributes.insert(id, attributes); id @@ -1002,6 +1005,10 @@ impl NodeInterner { &self.globals[global_id.0] } + pub fn get_global_mut(&mut self, global_id: GlobalId) -> &mut GlobalInfo { + &mut self.globals[global_id.0] + } + pub fn get_global_definition(&self, global_id: GlobalId) -> &DefinitionInfo { let global = self.get_global(global_id); self.definition(global.definition_id) From 6734bc793fcd8a441e1ef052513b95b80c871fb5 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 5 Jun 2024 10:49:56 +0100 Subject: [PATCH 20/24] Fix test --- compiler/noirc_frontend/src/hir/type_check/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index 65a3186b00..98e1cd9c72 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -452,6 +452,7 @@ pub mod test { PathResolution, PathResolutionError, PathResolutionResult, }; use crate::hir_def::expr::HirIdent; + use crate::hir_def::function::FunctionBody; use crate::hir_def::stmt::HirLetStatement; use crate::hir_def::stmt::HirPattern::Identifier; use crate::hir_def::types::Type; @@ -559,6 +560,7 @@ pub mod test { has_inline_attribute: false, all_generics: Vec::new(), parameter_idents: Vec::new(), + function_body: FunctionBody::Resolved, }; interner.push_fn_meta(func_meta, func_id); From 1a30098fbbdb79590284dd06f885e33c3989ba42 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 5 Jun 2024 11:02:14 +0100 Subject: [PATCH 21/24] Reset is_unconstrained --- compiler/noirc_frontend/src/elaborator/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index cc29f1098f..9403e12496 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -395,6 +395,7 @@ impl<'context> Elaborator<'context> { meta.function_body = FunctionBody::Resolved; self.trait_bounds.clear(); + self.in_unconstrained_fn = false; self.interner.update_fn(id, hir_func); self.current_function = old_function; self.current_item = old_item; From 79922d68119b637ac5c1091b1a3a8a17e1a11872 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 5 Jun 2024 11:31:08 +0100 Subject: [PATCH 22/24] Apply fix from #5176 --- compiler/noirc_frontend/src/elaborator/lints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/elaborator/lints.rs b/compiler/noirc_frontend/src/elaborator/lints.rs index da3e033cd4..d228588d36 100644 --- a/compiler/noirc_frontend/src/elaborator/lints.rs +++ b/compiler/noirc_frontend/src/elaborator/lints.rs @@ -41,7 +41,7 @@ pub(super) fn deprecated_function(interner: &NodeInterner, expr: ExprId) -> Opti /// as all unconstrained functions are not inlined and so /// associated attributes are disallowed. pub(super) fn inlining_attributes(func: &NoirFunction) -> Option { - if !func.def.is_unconstrained { + if func.def.is_unconstrained { let attributes = func.attributes().clone(); if attributes.is_no_predicates() { From 0a0d41d9a093a64e9671dfc67e1a7948ac54b952 Mon Sep 17 00:00:00 2001 From: jfecher Date: Wed, 5 Jun 2024 12:11:43 +0100 Subject: [PATCH 23/24] Update tooling/nargo_cli/build.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- tooling/nargo_cli/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tooling/nargo_cli/build.rs b/tooling/nargo_cli/build.rs index 899e80b333..25a6948978 100644 --- a/tooling/nargo_cli/build.rs +++ b/tooling/nargo_cli/build.rs @@ -313,10 +313,6 @@ fn compile_success_empty_{test_name}() {{ #[test] fn compile_success_empty_elaborator_{test_name}() {{ - - // We use a mocked backend for this test as we do not rely on the returned circuit size - // but we must call a backend as part of querying the number of opcodes in the circuit. - let test_program_dir = PathBuf::from("{test_dir}"); let mut cmd = Command::cargo_bin("nargo").unwrap(); cmd.arg("--program-dir").arg(test_program_dir); From 266335eec98d8212356b2759a73bac005a66ebe9 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 5 Jun 2024 12:12:37 +0100 Subject: [PATCH 24/24] Don't run the elaborator on frontend tests --- compiler/noirc_frontend/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 93182264ad..99215c8f17 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -81,7 +81,7 @@ pub(crate) fn get_program(src: &str) -> (ParsedModule, Context, Vec<(Compilation &mut context, program.clone().into_sorted(), root_file_id, - true, + false, &[], // No macro processors )); }