From 85702368b0ee215ab504d3fb2490c13202ddc8e8 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 7 Jan 2025 10:50:53 -0300 Subject: [PATCH 1/2] fix: don't fail parsing macro if there are parser warnings --- .../noirc_frontend/src/elaborator/comptime.rs | 2 +- .../src/elaborator/expressions.rs | 2 +- .../src/hir/comptime/interpreter.rs | 2 +- .../src/hir/comptime/interpreter/builtin.rs | 39 ++++++-------- .../interpreter/builtin/builtin_helpers.rs | 13 +++-- .../noirc_frontend/src/hir/comptime/value.rs | 51 ++++++++++++------- compiler/noirc_frontend/src/parser/parser.rs | 22 +++----- .../src/tests/metaprogramming.rs | 31 +++++++++++ 8 files changed, 99 insertions(+), 63 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 24c1e7d929e..f6ab755159a 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -247,7 +247,7 @@ impl<'context> Elaborator<'context> { if value != Value::Unit { let items = value - .into_top_level_items(location, self.interner) + .into_top_level_items(location, self) .map_err(|error| error.into_compilation_error_pair())?; self.add_items(items, generated_items, location); diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index c24cc1a9c86..73b8ef6a6bd 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -927,7 +927,7 @@ impl<'context> Elaborator<'context> { }; let location = Location::new(span, self.file); - match value.into_expression(self.interner, location) { + match value.into_expression(self, location) { Ok(new_expr) => { // At this point the Expression was already elaborated and we got a Value. // We'll elaborate this value turned into Expression to inline it and get diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index e9e37243e07..6224552c0af 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -1322,7 +1322,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { let bindings = unwrap_rc(bindings); let mut result = self.call_function(function_id, arguments, bindings, location)?; if call.is_macro_call { - let expr = result.into_expression(self.elaborator.interner, location)?; + let expr = result.into_expression(self.elaborator, location)?; let expr = self.elaborate_in_function(self.current_function, |elaborator| { elaborator.elaborate_expression(expr).0 }); diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index a1d244d9aca..8bf2d9c4f6e 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -158,7 +158,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "modulus_le_bits" => modulus_le_bits(arguments, location), "modulus_le_bytes" => modulus_le_bytes(arguments, location), "modulus_num_bits" => modulus_num_bits(arguments, location), - "quoted_as_expr" => quoted_as_expr(interner, arguments, return_type, location), + "quoted_as_expr" => quoted_as_expr(self, arguments, return_type, location), "quoted_as_module" => quoted_as_module(self, arguments, return_type, location), "quoted_as_trait_constraint" => quoted_as_trait_constraint(self, arguments, location), "quoted_as_type" => quoted_as_type(self, arguments, location), @@ -676,15 +676,19 @@ fn slice_insert( // fn as_expr(quoted: Quoted) -> Option fn quoted_as_expr( - interner: &NodeInterner, + interpreter: &mut Interpreter, arguments: Vec<(Value, Location)>, return_type: Type, location: Location, ) -> IResult { let argument = check_one_argument(arguments, location)?; - let result = - parse(interner, argument, Parser::parse_statement_or_expression_or_lvalue, "an expression"); + let result = parse( + interpreter, + argument, + Parser::parse_statement_or_expression_or_lvalue, + "an expression", + ); let value = result.ok().map( @@ -709,13 +713,8 @@ fn quoted_as_module( ) -> IResult { let argument = check_one_argument(arguments, location)?; - let path = parse( - interpreter.elaborator.interner, - argument, - Parser::parse_path_no_turbofish_or_error, - "a path", - ) - .ok(); + let path = + parse(interpreter, argument, Parser::parse_path_no_turbofish_or_error, "a path").ok(); let option_value = path.and_then(|path| { let module = interpreter .elaborate_in_function(interpreter.current_function, |elaborator| { @@ -734,12 +733,8 @@ fn quoted_as_trait_constraint( location: Location, ) -> IResult { let argument = check_one_argument(arguments, location)?; - let trait_bound = parse( - interpreter.elaborator.interner, - argument, - Parser::parse_trait_bound_or_error, - "a trait constraint", - )?; + let trait_bound = + parse(interpreter, argument, Parser::parse_trait_bound_or_error, "a trait constraint")?; let bound = interpreter .elaborate_in_function(interpreter.current_function, |elaborator| { elaborator.resolve_trait_bound(&trait_bound) @@ -756,8 +751,7 @@ fn quoted_as_type( location: Location, ) -> IResult { let argument = check_one_argument(arguments, location)?; - let typ = - parse(interpreter.elaborator.interner, argument, Parser::parse_type_or_error, "a type")?; + let typ = parse(interpreter, argument, Parser::parse_type_or_error, "a type")?; let typ = interpreter .elaborate_in_function(interpreter.current_function, |elab| elab.resolve_type(typ)); Ok(Value::Type(typ)) @@ -2453,7 +2447,7 @@ fn function_def_set_parameters( )?; let parameter_type = get_type((tuple.pop().unwrap(), parameters_argument_location))?; let parameter_pattern = parse( - interpreter.elaborator.interner, + interpreter, (tuple.pop().unwrap(), parameters_argument_location), Parser::parse_pattern_or_error, "a pattern", @@ -2570,12 +2564,11 @@ fn module_add_item( ) -> IResult { let (self_argument, item) = check_two_arguments(arguments, location)?; let module_id = get_module(self_argument)?; - let module_data = interpreter.elaborator.get_module(module_id); let parser = Parser::parse_top_level_items; - let top_level_statements = - parse(interpreter.elaborator.interner, item, parser, "a top-level item")?; + let top_level_statements = parse(interpreter, item, parser, "a top-level item")?; + let module_data = interpreter.elaborator.get_module(module_id); interpreter.elaborate_in_module(module_id, module_data.location.file, |elaborator| { let mut generated_items = CollectedItems::default(); diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs index cf90aab32e0..4fba4a6a1cc 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs @@ -8,7 +8,7 @@ use noirc_errors::Location; use crate::hir::comptime::display::tokens_to_string; use crate::hir::comptime::value::add_token_spans; use crate::lexer::Lexer; -use crate::parser::Parser; +use crate::parser::{Parser, ParserError}; use crate::{ ast::{ BlockExpression, ExpressionKind, Ident, IntegerBitSize, LValue, Pattern, Signedness, @@ -493,7 +493,7 @@ pub(super) fn lex(input: &str) -> Vec { } pub(super) fn parse<'a, T, F>( - interner: &NodeInterner, + interpreter: &mut Interpreter, (value, location): (Value, Location), parser: F, rule: &'static str, @@ -503,7 +503,12 @@ where { let tokens = get_quoted((value, location))?; let quoted = add_token_spans(tokens.clone(), location.span); - parse_tokens(tokens, quoted, interner, location, parser, rule) + let (result, warnings) = + parse_tokens(tokens, quoted, interpreter.elaborator.interner, location, parser, rule)?; + for warning in warnings { + interpreter.elaborator.errors.push((warning.into(), location.file)); + } + Ok(result) } pub(super) fn parse_tokens<'a, T, F>( @@ -513,7 +518,7 @@ pub(super) fn parse_tokens<'a, T, F>( location: Location, parsing_function: F, rule: &'static str, -) -> IResult +) -> IResult<(T, Vec)> where F: FnOnce(&mut Parser<'a>) -> T, { diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index e5c55e2b0be..b5496507e80 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -12,6 +12,7 @@ use crate::{ IntegerBitSize, LValue, Literal, Path, Pattern, Signedness, Statement, StatementKind, UnresolvedType, UnresolvedTypeData, }, + elaborator::Elaborator, hir::{def_map::ModuleId, type_check::generics::TraitGenerics}, hir_def::expr::{ HirArrayLiteral, HirConstructorExpression, HirExpression, HirIdent, HirLambda, HirLiteral, @@ -158,7 +159,7 @@ impl Value { pub(crate) fn into_expression( self, - interner: &mut NodeInterner, + elaborator: &mut Elaborator, location: Location, ) -> IResult { let kind = match self { @@ -212,22 +213,23 @@ impl Value { ExpressionKind::Literal(Literal::Str(unwrap_rc(value))) } Value::Function(id, typ, bindings) => { - let id = interner.function_definition_id(id); + let id = elaborator.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.span, location.file); - interner.push_expr_type(expr_id, typ); - interner.store_instantiation_bindings(expr_id, unwrap_rc(bindings)); + let expr_id = elaborator.interner.push_expr(HirExpression::Ident(ident, None)); + elaborator.interner.push_expr_location(expr_id, location.span, location.file); + elaborator.interner.push_expr_type(expr_id, typ); + elaborator.interner.store_instantiation_bindings(expr_id, unwrap_rc(bindings)); ExpressionKind::Resolved(expr_id) } Value::Tuple(fields) => { - let fields = try_vecmap(fields, |field| field.into_expression(interner, location))?; + let fields = + try_vecmap(fields, |field| field.into_expression(elaborator, location))?; ExpressionKind::Tuple(fields) } Value::Struct(fields, typ) => { let fields = try_vecmap(fields, |(name, field)| { - let field = field.into_expression(interner, location)?; + let field = field.into_expression(elaborator, location)?; Ok((Ident::new(unwrap_rc(name), location.span), field)) })?; @@ -246,12 +248,12 @@ impl Value { } Value::Array(elements, _) => { let elements = - try_vecmap(elements, |element| element.into_expression(interner, location))?; + try_vecmap(elements, |element| element.into_expression(elaborator, location))?; ExpressionKind::Literal(Literal::Array(ArrayLiteral::Standard(elements))) } Value::Slice(elements, _) => { let elements = - try_vecmap(elements, |element| element.into_expression(interner, location))?; + try_vecmap(elements, |element| element.into_expression(elaborator, location))?; ExpressionKind::Literal(Literal::Slice(ArrayLiteral::Standard(elements))) } Value::Quoted(tokens) => { @@ -262,12 +264,18 @@ impl Value { let parser = Parser::for_tokens(tokens_to_parse); return match parser.parse_result(Parser::parse_expression_or_error) { - Ok(expr) => Ok(expr), + Ok((expr, warnings)) => { + for warning in warnings { + elaborator.errors.push((warning.into(), location.file)); + } + + Ok(expr) + } Err(mut errors) => { let error = errors.swap_remove(0); let file = location.file; let rule = "an expression"; - let tokens = tokens_to_string(tokens, interner); + let tokens = tokens_to_string(tokens, elaborator.interner); Err(InterpreterError::FailedToParseMacro { error, file, tokens, rule }) } }; @@ -293,7 +301,7 @@ impl Value { | Value::Closure(..) | Value::ModuleDefinition(_) => { let typ = self.get_type().into_owned(); - let value = self.display(interner).to_string(); + let value = self.display(elaborator.interner).to_string(); return Err(InterpreterError::CannotInlineMacro { typ, value, location }); } }; @@ -533,16 +541,16 @@ impl Value { pub(crate) fn into_top_level_items( self, location: Location, - interner: &NodeInterner, + elaborator: &mut Elaborator, ) -> IResult> { let parser = Parser::parse_top_level_items; match self { Value::Quoted(tokens) => { - parse_tokens(tokens, interner, parser, location, "top-level item") + parse_tokens(tokens, elaborator, parser, location, "top-level item") } _ => { let typ = self.get_type().into_owned(); - let value = self.display(interner).to_string(); + let value = self.display(elaborator.interner).to_string(); Err(InterpreterError::CannotInlineMacro { value, typ, location }) } } @@ -556,7 +564,7 @@ pub(crate) fn unwrap_rc(rc: Rc) -> T { fn parse_tokens<'a, T, F>( tokens: Rc>, - interner: &NodeInterner, + elaborator: &mut Elaborator, parsing_function: F, location: Location, rule: &'static str, @@ -566,11 +574,16 @@ where { let parser = Parser::for_tokens(add_token_spans(tokens.clone(), location.span)); match parser.parse_result(parsing_function) { - Ok(expr) => Ok(expr), + Ok((expr, warnings)) => { + for warning in warnings { + elaborator.errors.push((warning.into(), location.file)); + } + Ok(expr) + } Err(mut errors) => { let error = errors.swap_remove(0); let file = location.file; - let tokens = tokens_to_string(tokens, interner); + let tokens = tokens_to_string(tokens, elaborator.interner); Err(InterpreterError::FailedToParseMacro { error, file, tokens, rule }) } } diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 9ce288c97fa..33c7a8aad51 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -128,9 +128,12 @@ impl<'a> Parser<'a> { } /// Invokes `parsing_function` (`parsing_function` must be some `parse_*` method of the parser) - /// and returns the result if the parser has no errors, and if the parser consumed all tokens. + /// and returns the result (and any warnings) if the parser has no errors, and if the parser consumed all tokens. /// Otherwise returns the list of errors. - pub fn parse_result(mut self, parsing_function: F) -> Result> + pub fn parse_result( + mut self, + parsing_function: F, + ) -> Result<(T, Vec), Vec> where F: FnOnce(&mut Parser<'a>) -> T, { @@ -140,23 +143,14 @@ impl<'a> Parser<'a> { return Err(self.errors); } - if self.errors.is_empty() { - Ok(item) + let all_warnings = self.errors.iter().all(|error| error.is_warning()); + if all_warnings { + Ok((item, self.errors)) } else { Err(self.errors) } } - /// Invokes `parsing_function` (`parsing_function` must be some `parse_*` method of the parser) - /// and returns the result if the parser has no errors, and if the parser consumed all tokens. - /// Otherwise returns None. - pub fn parse_option(self, parsing_function: F) -> Option - where - F: FnOnce(&mut Parser<'a>) -> Option, - { - self.parse_result(parsing_function).unwrap_or_default() - } - /// Bumps this parser by one token. Returns the token that was previously the "current" token. fn bump(&mut self) -> SpannedToken { self.previous_token_span = self.current_token_span; diff --git a/compiler/noirc_frontend/src/tests/metaprogramming.rs b/compiler/noirc_frontend/src/tests/metaprogramming.rs index 89a049ebc9d..675792bc2e8 100644 --- a/compiler/noirc_frontend/src/tests/metaprogramming.rs +++ b/compiler/noirc_frontend/src/tests/metaprogramming.rs @@ -10,6 +10,7 @@ use crate::{ resolution::errors::ResolverError, type_check::TypeCheckError, }, + parser::{ParserError, ParserErrorReason}, }; use super::{assert_no_errors, get_program_errors}; @@ -161,3 +162,33 @@ fn uses_correct_type_for_attribute_arguments() { "#; assert_no_errors(src); } + +#[test] +fn does_not_fail_to_parse_macro_on_parser_warning() { + let src = r#" + #[make_bar] + pub unconstrained fn foo() {} + + comptime fn make_bar(_: FunctionDefinition) -> Quoted { + quote { + pub fn bar() { + unsafe { + foo(); + } + } + } + } + + fn main() { + bar() + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::ParseError(parser_error) = &errors[0].0 else { + panic!("Expected a ParseError, got {:?}", errors[0].0); + }; + + assert!(matches!(parser_error.reason(), Some(ParserErrorReason::MissingSafetyComment))); +} From a9dd4e5a659e0de7a5ebab2fb077b12d7f2012b9 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 7 Jan 2025 10:57:06 -0300 Subject: [PATCH 2/2] Take Elaborator instead of Interpreter --- .../src/hir/comptime/interpreter/builtin.rs | 32 ++++++++++++------- .../interpreter/builtin/builtin_helpers.rs | 7 ++-- .../src/tests/metaprogramming.rs | 2 +- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 8bf2d9c4f6e..8a9fcf12e16 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -23,6 +23,7 @@ use crate::{ Pattern, Signedness, Statement, StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility, }, + elaborator::Elaborator, hir::{ comptime::{ errors::IResult, @@ -32,9 +33,11 @@ use crate::{ def_collector::dc_crate::CollectedItems, def_map::ModuleDefId, }, - hir_def::expr::{HirExpression, HirLiteral}, - hir_def::function::FunctionBody, - hir_def::{self}, + hir_def::{ + self, + expr::{HirExpression, HirLiteral}, + function::FunctionBody, + }, node_interner::{DefinitionKind, NodeInterner, TraitImplKind}, parser::{Parser, StatementOrExpressionOrLValue}, token::{Attribute, Token}, @@ -158,7 +161,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "modulus_le_bits" => modulus_le_bits(arguments, location), "modulus_le_bytes" => modulus_le_bytes(arguments, location), "modulus_num_bits" => modulus_num_bits(arguments, location), - "quoted_as_expr" => quoted_as_expr(self, arguments, return_type, location), + "quoted_as_expr" => quoted_as_expr(self.elaborator, arguments, return_type, location), "quoted_as_module" => quoted_as_module(self, arguments, return_type, location), "quoted_as_trait_constraint" => quoted_as_trait_constraint(self, arguments, location), "quoted_as_type" => quoted_as_type(self, arguments, location), @@ -676,7 +679,7 @@ fn slice_insert( // fn as_expr(quoted: Quoted) -> Option fn quoted_as_expr( - interpreter: &mut Interpreter, + elaborator: &mut Elaborator, arguments: Vec<(Value, Location)>, return_type: Type, location: Location, @@ -684,7 +687,7 @@ fn quoted_as_expr( let argument = check_one_argument(arguments, location)?; let result = parse( - interpreter, + elaborator, argument, Parser::parse_statement_or_expression_or_lvalue, "an expression", @@ -714,7 +717,8 @@ fn quoted_as_module( let argument = check_one_argument(arguments, location)?; let path = - parse(interpreter, argument, Parser::parse_path_no_turbofish_or_error, "a path").ok(); + parse(interpreter.elaborator, argument, Parser::parse_path_no_turbofish_or_error, "a path") + .ok(); let option_value = path.and_then(|path| { let module = interpreter .elaborate_in_function(interpreter.current_function, |elaborator| { @@ -733,8 +737,12 @@ fn quoted_as_trait_constraint( location: Location, ) -> IResult { let argument = check_one_argument(arguments, location)?; - let trait_bound = - parse(interpreter, argument, Parser::parse_trait_bound_or_error, "a trait constraint")?; + let trait_bound = parse( + interpreter.elaborator, + argument, + Parser::parse_trait_bound_or_error, + "a trait constraint", + )?; let bound = interpreter .elaborate_in_function(interpreter.current_function, |elaborator| { elaborator.resolve_trait_bound(&trait_bound) @@ -751,7 +759,7 @@ fn quoted_as_type( location: Location, ) -> IResult { let argument = check_one_argument(arguments, location)?; - let typ = parse(interpreter, argument, Parser::parse_type_or_error, "a type")?; + let typ = parse(interpreter.elaborator, argument, Parser::parse_type_or_error, "a type")?; let typ = interpreter .elaborate_in_function(interpreter.current_function, |elab| elab.resolve_type(typ)); Ok(Value::Type(typ)) @@ -2447,7 +2455,7 @@ fn function_def_set_parameters( )?; let parameter_type = get_type((tuple.pop().unwrap(), parameters_argument_location))?; let parameter_pattern = parse( - interpreter, + interpreter.elaborator, (tuple.pop().unwrap(), parameters_argument_location), Parser::parse_pattern_or_error, "a pattern", @@ -2566,7 +2574,7 @@ fn module_add_item( let module_id = get_module(self_argument)?; let parser = Parser::parse_top_level_items; - let top_level_statements = parse(interpreter, item, parser, "a top-level item")?; + let top_level_statements = parse(interpreter.elaborator, item, parser, "a top-level item")?; let module_data = interpreter.elaborator.get_module(module_id); interpreter.elaborate_in_module(module_id, module_data.location.file, |elaborator| { diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs index 4fba4a6a1cc..a3f84a00bfb 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs @@ -5,6 +5,7 @@ use acvm::FieldElement; use iter_extended::try_vecmap; use noirc_errors::Location; +use crate::elaborator::Elaborator; use crate::hir::comptime::display::tokens_to_string; use crate::hir::comptime::value::add_token_spans; use crate::lexer::Lexer; @@ -493,7 +494,7 @@ pub(super) fn lex(input: &str) -> Vec { } pub(super) fn parse<'a, T, F>( - interpreter: &mut Interpreter, + elaborator: &mut Elaborator, (value, location): (Value, Location), parser: F, rule: &'static str, @@ -504,9 +505,9 @@ where let tokens = get_quoted((value, location))?; let quoted = add_token_spans(tokens.clone(), location.span); let (result, warnings) = - parse_tokens(tokens, quoted, interpreter.elaborator.interner, location, parser, rule)?; + parse_tokens(tokens, quoted, elaborator.interner, location, parser, rule)?; for warning in warnings { - interpreter.elaborator.errors.push((warning.into(), location.file)); + elaborator.errors.push((warning.into(), location.file)); } Ok(result) } diff --git a/compiler/noirc_frontend/src/tests/metaprogramming.rs b/compiler/noirc_frontend/src/tests/metaprogramming.rs index 675792bc2e8..8256744e18f 100644 --- a/compiler/noirc_frontend/src/tests/metaprogramming.rs +++ b/compiler/noirc_frontend/src/tests/metaprogramming.rs @@ -10,7 +10,7 @@ use crate::{ resolution::errors::ResolverError, type_check::TypeCheckError, }, - parser::{ParserError, ParserErrorReason}, + parser::ParserErrorReason, }; use super::{assert_no_errors, get_program_errors};