diff --git a/compiler/noirc_frontend/src/elaborator/enums.rs b/compiler/noirc_frontend/src/elaborator/enums.rs index 5ff86d71d5b..9dc9bf7a8e3 100644 --- a/compiler/noirc_frontend/src/elaborator/enums.rs +++ b/compiler/noirc_frontend/src/elaborator/enums.rs @@ -361,12 +361,11 @@ impl Elaborator<'_> { // Each parameter of the enum variant function is used as a parameter of the enum // constructor expression let arguments = vecmap(¶meters.0, |(pattern, typ, _)| match pattern { - HirPattern::Identifier(ident) => { - let id = self.interner.push_expr(HirExpression::Ident(ident.clone(), None)); - self.interner.push_expr_type(id, typ.clone()); - self.interner.push_expr_location(id, location); - id - } + HirPattern::Identifier(ident) => self.interner.push_expr_full( + HirExpression::Ident(ident.clone(), None), + location, + typ.clone(), + ), _ => unreachable!(), }); @@ -376,12 +375,9 @@ impl Elaborator<'_> { variant_index, }); - let body = self.interner.push_expr(constructor); let enum_generics = self_type.borrow().generic_types(); let typ = Type::DataType(self_type.clone(), enum_generics); - self.interner.push_expr_type(body, typ); - self.interner.push_expr_location(body, location); - body + self.interner.push_expr_full(constructor, location, typ) } fn make_enum_variant_parameters( @@ -1271,9 +1267,7 @@ impl<'elab, 'ctx> MatchCompiler<'elab, 'ctx> { let variable = HirIdent::non_trait_method(variable, location); let rhs = HirExpression::Ident(HirIdent::non_trait_method(rhs, location), None); - let rhs = self.elaborator.interner.push_expr(rhs); - self.elaborator.interner.push_expr_type(rhs, rhs_type); - self.elaborator.interner.push_expr_location(rhs, location); + let rhs = self.elaborator.interner.push_expr_full(rhs, location, rhs_type); let let_ = HirStatement::Let(HirLetStatement { pattern: HirPattern::Identifier(variable), @@ -1285,17 +1279,12 @@ impl<'elab, 'ctx> MatchCompiler<'elab, 'ctx> { }); let body_type = self.elaborator.interner.id_type(body); - let let_ = self.elaborator.interner.push_stmt(let_); - let body = self.elaborator.interner.push_stmt(HirStatement::Expression(body)); - - self.elaborator.interner.push_stmt_location(let_, location); - self.elaborator.interner.push_stmt_location(body, location); + let let_ = self.elaborator.interner.push_stmt_full(let_, location); + let body = + self.elaborator.interner.push_stmt_full(HirStatement::Expression(body), location); let block = HirExpression::Block(HirBlockExpression { statements: vec![let_, body] }); - let block = self.elaborator.interner.push_expr(block); - self.elaborator.interner.push_expr_type(block, body_type); - self.elaborator.interner.push_expr_location(block, location); - block + self.elaborator.interner.push_expr_full(block, location, body_type) } /// Any case that isn't branched to when the match is finished must be covered by another diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index adac10f548e..7b1e27a0ce3 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -33,6 +33,7 @@ use crate::{ }, node_interner::{ DefinitionId, DefinitionKind, ExprId, FuncId, InternedStatementKind, StmtId, TraitItemId, + pusher::{HasLocation, PushedExpr}, }, shared::Signedness, signed_field::SignedField, @@ -108,9 +109,7 @@ impl Elaborator<'_> { } ExpressionKind::TypePath(path) => return self.elaborate_type_path(*path), }; - let id = self.interner.push_expr(hir_expr); - self.interner.push_expr_location(id, expr.location); - self.interner.push_expr_type(id, typ.clone()); + let id = self.interner.push_expr_full(hir_expr, expr.location, typ.clone()); if is_integer_literal { self.push_integer_literal_expr_id(id); @@ -450,10 +449,9 @@ impl Elaborator<'_> { self.handle_hir_ident(&hir_ident, var_scope_index, *location); let hir_expr = HirExpression::Ident(hir_ident.clone(), None); - let expr_id = self.interner.push_expr(hir_expr); - self.interner.push_expr_location(expr_id, *location); - let typ = self.type_check_variable(hir_ident, expr_id, None); - self.interner.push_expr_type(expr_id, typ.clone()); + let expr_id = self.intern_expr(hir_expr, *location); + let typ = self.type_check_variable(hir_ident, &expr_id, None); + let expr_id = self.intern_expr_type(expr_id, typ.clone()); capture_types.push(typ); fmt_str_idents.push(expr_id); @@ -499,8 +497,7 @@ impl Elaborator<'_> { trait_method_id, skip: skip_op, }); - let expr_id = self.interner.push_expr(expr); - self.interner.push_expr_location(expr_id, location); + let expr_id = self.intern_expr(expr, location); let typ = if skip_op { rhs_type @@ -510,12 +507,12 @@ impl Elaborator<'_> { result, &rhs_type, trait_method_id, - expr_id, + *expr_id, location, ) }; - self.interner.push_expr_type(expr_id, typ.clone()); + let expr_id = self.intern_expr_type(expr_id, typ.clone()); (expr_id, typ) } @@ -721,8 +718,9 @@ impl Elaborator<'_> { ); let func_type = - self.type_check_variable(function_name.clone(), function_id, generics.clone()); - self.interner.push_expr_type(function_id, func_type.clone()); + self.type_check_variable(function_name.clone(), &function_id, generics.clone()); + + let function_id = self.intern_expr_type(function_id, func_type.clone()); let func_arg_types = if let Type::Function(args, _, _, _) = &func_type { Some(args) } else { None }; @@ -863,9 +861,7 @@ impl Elaborator<'_> { let type_hint = if let Some(Type::Function(func_args, _, _, _)) = typ { Some(func_args) } else { None }; let (hir_expr, typ) = self.elaborate_lambda_with_parameter_type_hints(*lambda, type_hint); - let id = self.interner.push_expr(hir_expr); - self.interner.push_expr_location(id, location); - self.interner.push_expr_type(id, typ.clone()); + let id = self.interner.push_expr_full(hir_expr, location, typ.clone()); (id, typ) } @@ -1110,15 +1106,23 @@ impl Elaborator<'_> { // `is_offset` is only used when lhs is a reference and we want to return a reference to rhs let access = HirMemberAccess { lhs, rhs, is_offset }; let expr_id = self.intern_expr(HirExpression::MemberAccess(access.clone()), location); - let typ = self.type_check_member_access(access, expr_id, lhs_type, rhs_location); - self.interner.push_expr_type(expr_id, typ.clone()); + let typ = self.type_check_member_access(access, *expr_id, lhs_type, rhs_location); + let expr_id = self.intern_expr_type(expr_id, typ.clone()); (expr_id, typ, is_offset && is_reference) } - pub fn intern_expr(&mut self, expr: HirExpression, location: Location) -> ExprId { - let id = self.interner.push_expr(expr); - self.interner.push_expr_location(id, location); - id + /// Push a [HirExpression] with its [Location], with the [Type] to be followed up later. + pub fn intern_expr( + &mut self, + expr: HirExpression, + location: Location, + ) -> PushedExpr { + self.interner.push_expr(expr).push_location(self.interner, location) + } + + /// Follow up [Self::intern_expr] with the [Type]. + pub fn intern_expr_type(&mut self, expr_id: PushedExpr, typ: Type) -> ExprId { + expr_id.push_type(self.interner, typ) } fn elaborate_cast( @@ -1148,19 +1152,18 @@ impl Elaborator<'_> { rhs, }); - let expr_id = self.interner.push_expr(expr); - self.interner.push_expr_location(expr_id, location); + let expr_id = self.intern_expr(expr, location); let result = self.infix_operand_type_rules(&lhs_type, &operator, &rhs_type, location); let typ = self.handle_operand_type_rules_result( result, &lhs_type, Some(trait_id), - expr_id, + *expr_id, location, ); - self.interner.push_expr_type(expr_id, typ.clone()); + let expr_id = self.intern_expr_type(expr_id, typ.clone()); (expr_id, typ) } @@ -1279,12 +1282,9 @@ impl Elaborator<'_> { HirMatch::Failure { missing_case: false } }); - let tree = self.interner.push_expr(tree); - self.interner.push_expr_type(tree, result_type.clone()); - self.interner.push_expr_location(tree, location); + let tree = self.interner.push_expr_full(tree, location, result_type.clone()); - let tree = self.interner.push_stmt(HirStatement::Expression(tree)); - self.interner.push_stmt_location(tree, location); + let tree = self.interner.push_stmt_full(HirStatement::Expression(tree), location); let block = HirExpression::Block(HirBlockExpression { statements: vec![let_, tree] }); (block, result_type) @@ -1299,8 +1299,7 @@ impl Elaborator<'_> { let pattern = HirPattern::Identifier(HirIdent::non_trait_method(variable, location)); let let_ = HirStatement::Let(HirLetStatement::basic(pattern, typ, expr_id)); - let let_ = self.interner.push_stmt(let_); - self.interner.push_stmt_location(let_, location); + let let_ = self.interner.push_stmt_full(let_, location); (let_, variable) } @@ -1438,9 +1437,9 @@ impl Elaborator<'_> { let make_error = |this: &mut Self, error: InterpreterError| { let error: CompilationError = error.into(); this.push_err(error); - let error = this.interner.push_expr(HirExpression::Error); - this.interner.push_expr_location(error, location); - (error, Type::Error) + let typ = Type::Error; + let error = this.interner.push_expr_full(HirExpression::Error, location, typ.clone()); + (error, typ) }; let value = match value { @@ -1584,8 +1583,7 @@ impl Elaborator<'_> { impl_kind: ImplKind::TraitItem(trait_item), }; - let id = self.interner.push_expr(HirExpression::Ident(ident.clone(), None)); - self.interner.push_expr_location(id, location); + let id = self.intern_expr(HirExpression::Ident(ident.clone(), None), location); let mut bindings = TypeBindings::default(); @@ -1597,12 +1595,12 @@ impl Elaborator<'_> { let typ = self.type_check_variable_with_bindings( ident, - id, + &id, None, bindings, push_required_type_variables, ); - self.interner.push_expr_type(id, typ.clone()); + let id = self.intern_expr_type(id, typ.clone()); (id, typ) } } diff --git a/compiler/noirc_frontend/src/elaborator/function.rs b/compiler/noirc_frontend/src/elaborator/function.rs index 7ba6cdae59f..4ce398f2154 100644 --- a/compiler/noirc_frontend/src/elaborator/function.rs +++ b/compiler/noirc_frontend/src/elaborator/function.rs @@ -510,8 +510,7 @@ impl Elaborator<'_> { FunctionKind::Normal => { let return_type = func_meta.return_type(); let (block, body_type) = self.elaborate_block(body, Some(return_type)); - let expr_id = self.intern_expr(block, body_location); - self.interner.push_expr_type(expr_id, body_type.clone()); + let expr_id = self.interner.push_expr_full(block, body_location, body_type.clone()); (HirFunction::unchecked_from_expr(expr_id), body_type) } }; diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 550f71fd115..778d64e9aef 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -75,8 +75,7 @@ impl Elaborator<'_> { let location = statement.location; let (hir_statement, typ) = self.elaborate_statement_value_with_target_type(statement, target_type); - let id = self.interner.push_stmt(hir_statement); - self.interner.push_stmt_location(id, location); + let id = self.interner.push_stmt_full(hir_statement, location); (id, typ) } @@ -178,8 +177,7 @@ impl Elaborator<'_> { if new_statements.is_empty() { (assign, Type::Unit) } else { - let assign = self.interner.push_stmt(assign); - self.interner.push_stmt_location(assign, expr_location); + let assign = self.interner.push_stmt_full(assign, expr_location); new_statements.push(assign); let block = HirExpression::Block(HirBlockExpression { statements: new_statements }); let block = self.interner.push_expr_full(block, expr_location, Type::Unit); @@ -605,8 +603,7 @@ impl Elaborator<'_> { let pattern = HirPattern::Identifier(ident); let let_ = HirStatement::Let(HirLetStatement::basic(pattern, typ, expr)); - let let_ = self.interner.push_stmt(let_); - self.interner.push_stmt_location(let_, location); + let let_ = self.interner.push_stmt_full(let_, location); Some((let_, ident_id)) } diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 04359f2b076..52e7128098e 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -1122,12 +1122,14 @@ impl Elaborator<'_> { if let Type::Reference(element, _mut) = typ.follow_bindings() { let location = self.interner.id_location(object); - let object = self.interner.push_expr(HirExpression::Prefix(HirPrefixExpression::new( - UnaryOp::Dereference { implicitly_added: true }, - object, - ))); - self.interner.push_expr_type(object, element.as_ref().clone()); - self.interner.push_expr_location(object, location); + let object = self.interner.push_expr_full( + HirExpression::Prefix(HirPrefixExpression::new( + UnaryOp::Dereference { implicitly_added: true }, + object, + )), + location, + element.as_ref().clone(), + ); // Recursively dereference to allow for converting &mut &mut T to T self.insert_auto_dereferences(object, *element) @@ -1686,16 +1688,19 @@ impl Elaborator<'_> { let dereference_lhs = |this: &mut Self, lhs_type, element| { let old_lhs = *access_lhs; - *access_lhs = this.interner.push_expr(HirExpression::Prefix(HirPrefixExpression::new( - UnaryOp::Dereference { implicitly_added: true }, - old_lhs, - ))); - this.interner.push_expr_type(old_lhs, lhs_type); - this.interner.push_expr_type(*access_lhs, element); - let old_location = this.interner.id_location(old_lhs); let location = Location::new(location.span, old_location.file); - this.interner.push_expr_location(*access_lhs, location); + + *access_lhs = this.interner.push_expr_full( + HirExpression::Prefix(HirPrefixExpression::new( + UnaryOp::Dereference { implicitly_added: true }, + old_lhs, + )), + location, + element, + ); + + this.interner.push_expr_type(old_lhs, lhs_type); }; // If this access is just a field offset, we want to avoid dereferencing @@ -2164,12 +2169,14 @@ impl Elaborator<'_> { // If that didn't work, then wrap the whole expression in an `&mut` *object = new_object.unwrap_or_else(|| { - let new_object = self.interner.push_expr(HirExpression::Prefix( - HirPrefixExpression::new(UnaryOp::Reference { mutable }, *object), - )); - self.interner.push_expr_type(new_object, new_type); - self.interner.push_expr_location(new_object, location); - new_object + self.interner.push_expr_full( + HirExpression::Prefix(HirPrefixExpression::new( + UnaryOp::Reference { mutable }, + *object, + )), + location, + new_type, + ) }); } // Otherwise if the object type is a mutable reference and the method is not, insert as diff --git a/compiler/noirc_frontend/src/elaborator/variable.rs b/compiler/noirc_frontend/src/elaborator/variable.rs index 6c68bc5adf7..3dfaedbe78f 100644 --- a/compiler/noirc_frontend/src/elaborator/variable.rs +++ b/compiler/noirc_frontend/src/elaborator/variable.rs @@ -13,6 +13,7 @@ use crate::elaborator::types::{SELF_TYPE_NAME, TraitPathResolutionMethod}; use crate::hir::def_collector::dc_crate::CompilationError; use crate::hir::type_check::TypeCheckError; use crate::hir_def::expr::{HirExpression, HirIdent, HirMethodReference, ImplKind, TraitItem}; +use crate::node_interner::pusher::{HasLocation, PushedExpr}; use crate::node_interner::{DefinitionId, DefinitionInfo, DefinitionKind, ExprId, TraitImplKind}; use crate::{Kind, Type, TypeBindings}; use iter_extended::vecmap; @@ -91,19 +92,18 @@ impl Elaborator<'_> { } } - let id = self.interner.push_expr(HirExpression::Ident(expr.clone(), generics.clone())); + let id = self.intern_expr(HirExpression::Ident(expr.clone(), generics.clone()), location); - self.interner.push_expr_location(id, location); // TODO: set this to `true`. See https://github.com/noir-lang/noir/issues/8687 let push_required_type_variables = self.current_trait.is_none(); let typ = self.type_check_variable_with_bindings( expr, - id, + &id, generics, bindings, push_required_type_variables, ); - self.interner.push_expr_type(id, typ.clone()); + let id = self.intern_expr_type(id, typ.clone()); // If this variable it a comptime local variable, use its current value as the final expression if is_comptime_local { @@ -152,9 +152,7 @@ impl Elaborator<'_> { { let hir_ident = HirIdent::non_trait_method(definition_id, location); let hir_expr = HirExpression::Ident(hir_ident, None); - let id = self.interner.push_expr(hir_expr); - self.interner.push_expr_location(id, location); - self.interner.push_expr_type(id, numeric_type.clone()); + let id = self.interner.push_expr_full(hir_expr, location, numeric_type.clone()); return Some((id, numeric_type)); } @@ -210,7 +208,7 @@ impl Elaborator<'_> { /// Solve any generics that are part of the path before the function, for example: /// /// ```noir - /// foo::Bar::::baz + /// foo::Bar::::baz /// ``` /// Solve `` above fn resolve_item_turbofish_and_self_type( @@ -339,11 +337,11 @@ impl Elaborator<'_> { }; let ident = HirIdent { location: ident_location, id, impl_kind }; - let id = self.interner.push_expr(HirExpression::Ident(ident.clone(), generics.clone())); - self.interner.push_expr_location(id, ident_location); + let id = + self.intern_expr(HirExpression::Ident(ident.clone(), generics.clone()), ident_location); - let typ = self.type_check_variable(ident, id, generics); - self.interner.push_expr_type(id, typ.clone()); + let typ = self.type_check_variable(ident, &id, generics); + let id = self.intern_expr_type(id, typ.clone()); (id, typ) } @@ -400,7 +398,7 @@ impl Elaborator<'_> { pub(crate) fn type_check_variable( &mut self, ident: HirIdent, - expr_id: ExprId, + expr_id: &PushedExpr, generics: Option>, ) -> Type { let bindings = TypeBindings::default(); @@ -418,7 +416,7 @@ impl Elaborator<'_> { pub(crate) fn type_check_variable_with_bindings( &mut self, ident: HirIdent, - expr_id: ExprId, + expr_id: &PushedExpr, generics: Option>, mut bindings: TypeBindings, push_required_type_variables: bool, @@ -449,7 +447,7 @@ impl Elaborator<'_> { _ => 0, }); - let location = self.interner.expr_location(&expr_id); + let location = self.interner.expr_location(expr_id); // This instantiates a trait's generics as well which need to be set // when the constraint below is later solved for when the function is @@ -463,11 +461,11 @@ impl Elaborator<'_> { let trait_generics = method.constraint.trait_bound.trait_generics.clone(); let object_type = method.constraint.typ; let trait_impl = TraitImplKind::Assumed { object_type, trait_generics }; - self.interner.select_impl_for_expression(expr_id, trait_impl); + self.interner.select_impl_for_expression(**expr_id, trait_impl); } else { self.push_trait_constraint( method.constraint, - expr_id, + **expr_id, true, // this constraint should lead to choosing a trait impl method ); } @@ -511,7 +509,7 @@ impl Elaborator<'_> { constraint.apply_bindings(&bindings); self.push_trait_constraint( - constraint, expr_id, + constraint, **expr_id, false, // This constraint shouldn't lead to choosing a trait impl method ); } @@ -529,7 +527,7 @@ impl Elaborator<'_> { } } - self.interner.store_instantiation_bindings(expr_id, bindings); + self.interner.store_instantiation_bindings(**expr_id, bindings); typ } diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 85cb1d8dc66..89fb6f2ebad 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -2531,8 +2531,7 @@ fn function_def_as_typed_expr( }; let generics = None; let hir_expr = HirExpression::Ident(hir_ident.clone(), generics.clone()); - let expr_id = interpreter.elaborator.interner.push_expr(hir_expr); - interpreter.elaborator.interner.push_expr_location(expr_id, location); + let expr_id = interpreter.elaborator.intern_expr(hir_expr, location); let reason = Some(ElaborateReason::EvaluatingComptimeCall( "FunctionDefinition::as_typed_expr", location, @@ -2543,13 +2542,13 @@ fn function_def_as_typed_expr( let push_required_type_variables = false; elaborator.type_check_variable_with_bindings( hir_ident, - expr_id, + &expr_id, generics, bindings, push_required_type_variables, ) }); - interpreter.elaborator.interner.push_expr_type(expr_id, typ); + let expr_id = interpreter.elaborator.intern_expr_type(expr_id, typ); Ok(Value::TypedExpr(TypedExpr::ExprId(expr_id))) } diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 08065fd613b..f5f9ba3b323 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -244,9 +244,11 @@ impl Value { let id = elaborator.interner.function_definition_id(id); let impl_kind = ImplKind::NotATraitMethod; let ident = HirIdent { location, id, impl_kind }; - let expr_id = elaborator.interner.push_expr(HirExpression::Ident(ident, None)); - elaborator.interner.push_expr_location(expr_id, location); - elaborator.interner.push_expr_type(expr_id, typ); + let expr_id = elaborator.interner.push_expr_full( + HirExpression::Ident(ident, None), + location, + typ, + ); elaborator.interner.store_instantiation_bindings(expr_id, unwrap_rc(bindings)); ExpressionKind::Resolved(expr_id) } @@ -412,9 +414,8 @@ impl Value { let id = interner.function_definition_id(id); let impl_kind = ImplKind::NotATraitMethod; let ident = HirIdent { location, id, impl_kind }; - let expr_id = interner.push_expr(HirExpression::Ident(ident, None)); - interner.push_expr_location(expr_id, location); - interner.push_expr_type(expr_id, typ); + let expr_id = + interner.push_expr_full(HirExpression::Ident(ident, None), location, typ); interner.store_instantiation_bindings(expr_id, unwrap_rc(bindings)); return Ok(expr_id); } @@ -495,9 +496,7 @@ impl Value { } }; - let id = interner.push_expr(expression); - interner.push_expr_location(id, location); - interner.push_expr_type(id, typ); + let id = interner.push_expr_full(expression, location, typ); Ok(id) } diff --git a/compiler/noirc_frontend/src/hir_def/expr.rs b/compiler/noirc_frontend/src/hir_def/expr.rs index 5dd03ae4e0d..43022b31d8c 100644 --- a/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/compiler/noirc_frontend/src/hir_def/expr.rs @@ -5,6 +5,7 @@ use noirc_errors::Location; use crate::Shared; use crate::ast::{BinaryOp, BinaryOpKind, Ident, UnaryOp}; use crate::hir::type_check::generics::TraitGenerics; +use crate::node_interner::pusher::{HasLocation, PushedExpr}; use crate::node_interner::{ DefinitionId, DefinitionKind, ExprId, FuncId, NodeInterner, StmtId, TraitId, TraitItemId, }; @@ -264,7 +265,7 @@ impl HirMethodReference { generics: Option>, location: Location, interner: &mut NodeInterner, - ) -> (ExprId, HirIdent) { + ) -> (PushedExpr, HirIdent) { let (id, impl_kind) = match self { HirMethodReference::FuncId(func_id) => { (interner.function_definition_id(func_id), ImplKind::NotATraitMethod) @@ -279,8 +280,9 @@ impl HirMethodReference { } }; let func_var = HirIdent { location, id, impl_kind }; - let func = interner.push_expr(HirExpression::Ident(func_var.clone(), generics)); - interner.push_expr_location(func, location); + let func = interner + .push_expr(HirExpression::Ident(func_var.clone(), generics)) + .push_location(interner, location); (func, func_var) } } diff --git a/compiler/noirc_frontend/src/hir_def/types/unification.rs b/compiler/noirc_frontend/src/hir_def/types/unification.rs index 74200e66a50..ff353a0a7a2 100644 --- a/compiler/noirc_frontend/src/hir_def/types/unification.rs +++ b/compiler/noirc_frontend/src/hir_def/types/unification.rs @@ -659,26 +659,24 @@ fn invoke_function_on_expression( let method_id = interner.function_definition_id(method); let location = interner.expr_location(&expression); let as_slice = HirExpression::Ident(HirIdent::non_trait_method(method_id, location), None); - let func = interner.push_expr(as_slice); + let func_type = Type::Function( + vec![expression_type.clone()], + Box::new(target_type.clone()), + Box::new(Type::Unit), + false, + ); + let func = interner.push_expr_full(as_slice, location, func_type); // Copy the expression and give it a new ExprId. The old one // will be mutated in place into a Call expression. let argument = interner.expression(&expression); - let argument = interner.push_expr(argument); - interner.push_expr_type(argument, expression_type.clone()); - interner.push_expr_location(argument, location); + let argument = interner.push_expr_full(argument, location, expression_type); let arguments = vec![argument]; let is_macro_call = false; let call = HirExpression::Call(HirCallExpression { func, arguments, location, is_macro_call }); interner.replace_expr(&expression, call); - - interner.push_expr_location(func, location); - interner.push_expr_type(expression, target_type.clone()); - - let func_type = - Type::Function(vec![expression_type], Box::new(target_type), Box::new(Type::Unit), false); - interner.push_expr_type(func, func_type); + interner.push_expr_type(expression, target_type); } #[cfg(test)] diff --git a/compiler/noirc_frontend/src/monomorphization/debug.rs b/compiler/noirc_frontend/src/monomorphization/debug.rs index 06e20424b27..1502e91958c 100644 --- a/compiler/noirc_frontend/src/monomorphization/debug.rs +++ b/compiler/noirc_frontend/src/monomorphization/debug.rs @@ -156,9 +156,11 @@ impl Monomorphizer<'_> { cursor_type = element_type_at_index(cursor_type, field_index); let integer = HirLiteral::Integer(SignedField::positive(field_index)); - let index_id = self.interner.push_expr(HirExpression::Literal(integer)); - self.interner.push_expr_type(index_id, crate::Type::FieldElement); - self.interner.push_expr_location(index_id, call.location); + let index_id = self.interner.push_expr_full( + HirExpression::Literal(integer), + call.location, + crate::Type::FieldElement, + ); arguments[DEBUG_MEMBER_FIELD_INDEX_ARG_SLOT + i] = self.expr(index_id)?; } else { // array/string element using constant index @@ -182,11 +184,8 @@ impl Monomorphizer<'_> { fn intern_var_id(&mut self, var_id: DebugVarId, location: &Location) -> ExprId { let value = SignedField::positive(var_id.0); let var_id_literal = HirLiteral::Integer(value); - let expr_id = self.interner.push_expr(HirExpression::Literal(var_id_literal)); let u32 = crate::Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo); - self.interner.push_expr_type(expr_id, u32); - self.interner.push_expr_location(expr_id, *location); - expr_id + self.interner.push_expr_full(HirExpression::Literal(var_id_literal), *location, u32) } } diff --git a/compiler/noirc_frontend/src/node_interner/globals.rs b/compiler/noirc_frontend/src/node_interner/globals.rs index adb61960e1a..5365beaa1fd 100644 --- a/compiler/noirc_frontend/src/node_interner/globals.rs +++ b/compiler/noirc_frontend/src/node_interner/globals.rs @@ -96,14 +96,11 @@ impl NodeInterner { comptime: bool, visibility: ItemVisibility, ) -> GlobalId { - let statement = self.push_stmt(HirStatement::Error); - let location = name.location(); + let statement = self.push_stmt_full(HirStatement::Error, name.location()); - let id = self.push_global( + self.push_global( name, local_id, crate_id, statement, file, attributes, mutable, comptime, visibility, - ); - self.push_stmt_location(statement, location); - id + ) } pub fn get_global(&self, global_id: GlobalId) -> &GlobalInfo { diff --git a/compiler/noirc_frontend/src/node_interner/mod.rs b/compiler/noirc_frontend/src/node_interner/mod.rs index dde5b3c6831..2c1f45f0618 100644 --- a/compiler/noirc_frontend/src/node_interner/mod.rs +++ b/compiler/noirc_frontend/src/node_interner/mod.rs @@ -20,6 +20,7 @@ use crate::hir::def_map::{LocalModuleId, ModuleDefId, ModuleId}; use crate::hir::type_check::generics::TraitGenerics; use crate::hir_def::traits::NamedType; use crate::locations::AutoImportEntry; +use crate::node_interner::pusher::PushedExpr; use crate::token::MetaAttribute; use crate::token::MetaAttributeName; @@ -45,6 +46,8 @@ mod methods; mod reexports; mod trait_impl; +pub mod pusher; + pub use dependency::DependencyId; use globals::GlobalInfo; pub use globals::{GlobalId, GlobalValue}; @@ -483,22 +486,22 @@ impl Default for NodeInterner { // XXX: Add check that insertions are not overwrites for maps // XXX: Maybe change push to intern, and remove comments impl NodeInterner { - /// Interns a HIR statement. - pub fn push_stmt(&mut self, stmt: HirStatement) -> StmtId { - StmtId(self.nodes.insert(Node::Statement(stmt))) + /// Intern a HIR statement with everything needed for it (location). + pub fn push_stmt_full(&mut self, stmt: HirStatement, location: Location) -> StmtId { + let id = StmtId(self.nodes.insert(Node::Statement(stmt))); + self.push_stmt_location(id, location); + id } - /// Interns a HIR expression. - pub fn push_expr(&mut self, expr: HirExpression) -> ExprId { - ExprId(self.nodes.insert(Node::Expression(expr))) + + /// Interns a HIR expression, with the location and type information pushed as follow ups. + pub fn push_expr(&mut self, expr: HirExpression) -> PushedExpr { + PushedExpr::new(ExprId(self.nodes.insert(Node::Expression(expr)))) } - /// Intern an expression with everything needed for it (location & Type) + /// Intern an expression with everything needed for it (location & type) /// instead of requiring they be pushed later. pub fn push_expr_full(&mut self, expr: HirExpression, location: Location, typ: Type) -> ExprId { - let id = self.push_expr(expr); - self.push_expr_location(id, location); - self.push_expr_type(id, typ); - id + self.push_expr(expr).push_location(self, location).push_type(self, typ) } /// Stores the span for an interned expression. diff --git a/compiler/noirc_frontend/src/node_interner/pusher.rs b/compiler/noirc_frontend/src/node_interner/pusher.rs new file mode 100644 index 00000000000..79ce0d7f876 --- /dev/null +++ b/compiler/noirc_frontend/src/node_interner/pusher.rs @@ -0,0 +1,68 @@ +//! Helper constructs to ensure that no parts are forgotten when pushing expressions and statements piecemeal. +use std::{marker::PhantomData, ops::Deref}; + +use noirc_errors::Location; + +use crate::{ + Type, + node_interner::{ExprId, NodeInterner}, +}; + +pub struct HasNothing; +pub struct HasLocation; + +pub struct PushedExpr { + id: ExprId, + has_location: bool, + has_type: bool, + status: PhantomData, +} + +impl PushedExpr { + /// Create a new pusher that will need the location and the type pushed. + pub fn new(id: ExprId) -> Self { + Self { id, has_location: false, has_type: false, status: PhantomData } + } + + /// Push the location first, then the type. + pub fn push_location( + self, + interner: &mut NodeInterner, + location: Location, + ) -> PushedExpr { + let id = self.id; + interner.push_expr_location(id, location); + std::mem::forget(self); + PushedExpr { id, has_location: true, has_type: false, status: PhantomData } + } +} + +impl PushedExpr { + /// Push the type after the location, returning the ID as there are no more missing pieces. + pub fn push_type(mut self, interner: &mut NodeInterner, typ: Type) -> ExprId { + interner.push_expr_type(self.id, typ); + self.has_type = true; + self.id + } +} + +/// Give convenient access to the ID in case it is needed to make the next piece available. +impl Deref for PushedExpr { + type Target = ExprId; + + fn deref(&self) -> &Self::Target { + &self.id + } +} + +/// Panic if we dropped the pusher without having pushed both location and type. +impl Drop for PushedExpr { + fn drop(&mut self) { + if !self.has_location { + panic!("location hasn't been pushed for {:?}", self.id); + } + if !self.has_type { + panic!("type hasn't been pushed for {:?}", self.id); + } + } +}