diff --git a/Cargo.lock b/Cargo.lock index 6bd62e868a2..29d76601adb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1669,6 +1669,7 @@ dependencies = [ "serde", "serde_json", "sway-core", + "sway-error", "sway-types", "sway-utils", "term-table", @@ -5550,7 +5551,6 @@ dependencies = [ "serde", "serde_json", "sha2 0.9.9", - "smallvec", "strum", "sway-ast", "sway-error", @@ -5572,6 +5572,7 @@ dependencies = [ "extension-trait", "num-bigint", "num-traits", + "smallvec", "sway-ast", "sway-types", "thiserror", @@ -5931,6 +5932,7 @@ dependencies = [ "revm", "serde_json", "sway-core", + "sway-error", "sway-ir", "sway-types", "sway-utils", diff --git a/forc-pkg/src/manifest.rs b/forc-pkg/src/manifest.rs index 77cdf38bae2..b5904c11efa 100644 --- a/forc-pkg/src/manifest.rs +++ b/forc-pkg/src/manifest.rs @@ -8,6 +8,7 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; +use sway_error::handler::Handler; use sway_core::{fuel_prelude::fuel_tx, language::parsed::TreeType, parse_tree_type, BuildTarget}; use sway_utils::constants; @@ -391,10 +392,13 @@ impl PackageManifestFile { /// Parse and return the associated project's program type. pub fn program_type(&self) -> Result { let entry_string = self.entry_string()?; - let parse_res = parse_tree_type(entry_string); - parse_res - .value - .ok_or_else(|| parsing_failed(&self.project.name, parse_res.errors)) + let handler = Handler::default(); + let parse_res = parse_tree_type(&handler, entry_string); + + parse_res.map_err(|_| { + let (errors, _warnings) = handler.consume(); + parsing_failed(&self.project.name, errors) + }) } /// Given the current directory and expected program type, diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index b6c53d35bc4..c3fdfd1159b 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -42,9 +42,9 @@ use sway_core::{ semantic_analysis::namespace, source_map::SourceMap, transform::AttributeKind, - BuildTarget, CompileResult, Engines, FinalizedEntry, + BuildTarget, Engines, FinalizedEntry, }; -use sway_error::{error::CompileError, warning::CompileWarning}; +use sway_error::{error::CompileError, handler::Handler, warning::CompileWarning}; use sway_types::{Ident, Span, Spanned}; use sway_utils::{constants, time_expr, PerformanceData, PerformanceMetric}; use tracing::{info, warn}; @@ -1658,7 +1658,8 @@ pub fn dependency_namespace( } } - namespace.star_import_with_reexports( + let _ = namespace.star_import_with_reexports( + &Handler::default(), &[CORE, PRELUDE].map(|s| Ident::new_no_span(s.into())), &[], engines, @@ -1666,7 +1667,8 @@ pub fn dependency_namespace( ); if has_std_dep(graph, node) { - namespace.star_import_with_reexports( + let _ = namespace.star_import_with_reexports( + &Handler::default(), &[STD, PRELUDE].map(|s| Ident::new_no_span(s.into())), &[], engines, @@ -1761,17 +1763,27 @@ pub fn compile( sway_build_config(pkg.manifest_file.dir(), &entry_path, pkg.target, profile)?; let terse_mode = profile.terse; let reverse_results = profile.reverse_results; - let fail = |warnings, errors| { - print_on_failure(engines.se(), terse_mode, warnings, errors, reverse_results); + let fail = |handler: Handler| { + let (errors, warnings) = handler.consume(); + print_on_failure( + engines.se(), + terse_mode, + &warnings, + &errors, + reverse_results, + ); bail!("Failed to compile {}", pkg.name); }; let source = pkg.manifest_file.entry_string()?; + let handler = Handler::default(); + // First, compile to an AST. We'll update the namespace and check for JSON ABI output. let ast_res = time_expr!( "compile to ast", "compile_to_ast", sway_core::compile_to_ast( + &handler, engines, source, namespace, @@ -1782,12 +1794,13 @@ pub fn compile( Some(sway_build_config.clone()), metrics ); - let programs = match ast_res.value.as_ref() { - None => return fail(&ast_res.warnings, &ast_res.errors), - Some(programs) => programs, + + let programs = match ast_res { + Err(_) => return fail(handler), + Ok(programs) => programs, }; let typed_program = match programs.typed.as_ref() { - None => return fail(&ast_res.warnings, &ast_res.errors), + None => return fail(handler), Some(typed_program) => typed_program, }; @@ -1800,14 +1813,14 @@ pub fn compile( let namespace = typed_program.root.namespace.clone().into(); - if !ast_res.errors.is_empty() { - return fail(&ast_res.warnings, &ast_res.errors); + if handler.has_error() { + return fail(handler); } let asm_res = time_expr!( "compile ast to asm", "compile_ast_to_asm", - sway_core::ast_to_asm(engines, &ast_res, &sway_build_config), + sway_core::ast_to_asm(&handler, engines, &programs, &sway_build_config), Some(sway_build_config.clone()), metrics ); @@ -1834,8 +1847,8 @@ pub fn compile( BuildTarget::EVM => { // Merge the ABI output of ASM gen with ABI gen to handle internal constructors // generated by the ASM backend. - let mut ops = match &asm_res.value { - Some(ref asm) => match &asm.0.abi { + let mut ops = match &asm_res { + Ok(ref asm) => match &asm.0.abi { Some(ProgramABI::Evm(ops)) => ops.clone(), _ => vec![], }, @@ -1859,7 +1872,6 @@ pub fn compile( }; let entries = asm_res - .value .as_ref() .map(|asm| asm.0.entries.clone()) .unwrap_or_default(); @@ -1867,29 +1879,30 @@ pub fn compile( .iter() .map(|finalized_entry| PkgEntry::from_finalized_entry(finalized_entry, engines)) .collect::>()?; + + let asm = match asm_res { + Err(_) => return fail(handler), + Ok(asm) => asm, + }; + let bc_res = time_expr!( "compile asm to bytecode", "compile_asm_to_bytecode", - sway_core::asm_to_bytecode(asm_res, source_map, engines.se()), + sway_core::asm_to_bytecode(&handler, asm, source_map, engines.se()), Some(sway_build_config), metrics ); - let errored = - !bc_res.errors.is_empty() || (!bc_res.warnings.is_empty() && profile.error_on_warnings); + let errored = handler.has_error() || (handler.has_warning() && profile.error_on_warnings); - let compiled = match bc_res.value { - Some(compiled) if !errored => compiled, - _ => return fail(&bc_res.warnings, &bc_res.errors), + let compiled = match bc_res { + Ok(compiled) if !errored => compiled, + _ => return fail(handler), }; - print_warnings( - engines.se(), - terse_mode, - &pkg.name, - &bc_res.warnings, - &tree_type, - ); + let (_, warnings) = handler.consume(); + + print_warnings(engines.se(), terse_mode, &pkg.name, &warnings, &tree_type); // TODO: This should probably be in `fuel_abi_json::generate_json_abi_program`? // If ABI requires knowing config offsets, they should be inputs to ABI gen. @@ -1918,7 +1931,7 @@ pub fn compile( tree_type, bytecode, namespace, - warnings: bc_res.warnings, + warnings, metrics, }; Ok(compiled_package) @@ -2582,7 +2595,7 @@ pub fn check( terse_mode: bool, include_tests: bool, engines: &Engines, -) -> anyhow::Result>> { +) -> anyhow::Result, Handler)>> { let mut lib_namespace_map = Default::default(); let mut source_map = SourceMap::new(); // During `check`, we don't compile so this stays empty. @@ -2629,19 +2642,22 @@ pub fn check( .include_tests(include_tests); let mut metrics = PerformanceData::default(); + let input = manifest.entry_string()?; + let handler = Handler::default(); let programs_res = sway_core::compile_to_ast( + &handler, engines, - manifest.entry_string()?, + input, dep_namespace, Some(&build_config), &pkg.name, &mut metrics, ); - let programs = match programs_res.value.as_ref() { - Some(programs) => programs, + let programs = match programs_res.as_ref() { + Ok(programs) => programs, _ => { - results.push(programs_res); + results.push((programs_res.ok(), handler)); return Ok(results); } }; @@ -2666,12 +2682,12 @@ pub fn check( source_map.insert_dependency(manifest.dir()); } None => { - results.push(programs_res); + results.push((programs_res.ok(), handler)); return Ok(results); } } - results.push(programs_res) + results.push((programs_res.ok(), handler)) } if results.is_empty() { diff --git a/forc-plugins/forc-doc/src/main.rs b/forc-plugins/forc-doc/src/main.rs index a9320c32386..11a091bee2b 100644 --- a/forc-plugins/forc-doc/src/main.rs +++ b/forc-plugins/forc-doc/src/main.rs @@ -104,12 +104,12 @@ pub fn main() -> Result<()> { let graph = plan.graph(); let manifest_map = plan.manifest_map(); - for (node, compile_result) in order.iter().zip(compile_results) { + for (node, (compile_result, _handler)) in order.iter().zip(compile_results) { let id = &graph[*node].id(); if let Some(pkg_manifest_file) = manifest_map.get(id) { let manifest_file = ManifestFile::from_dir(pkg_manifest_file.path())?; - let ty_program = match compile_result.value.and_then(|programs| programs.typed) { + let ty_program = match compile_result.and_then(|programs| programs.typed) { Some(ty_program) => ty_program, _ => bail!( "documentation could not be built from manifest located at '{}'", @@ -129,8 +129,8 @@ pub fn main() -> Result<()> { } else { let ty_program = match compile_results .pop() - .and_then(|compilation| compilation.value) - .and_then(|programs| programs.typed) + .and_then(|(programs, _handler)| programs) + .and_then(|p| p.typed) { Some(ty_program) => ty_program, _ => bail!( diff --git a/forc/Cargo.toml b/forc/Cargo.toml index eb21c71f1ad..e5a1aea1f44 100644 --- a/forc/Cargo.toml +++ b/forc/Cargo.toml @@ -32,6 +32,7 @@ hex = "0.4.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.73" sway-core = { version = "0.42.1", path = "../sway-core" } +sway-error = { version = "0.42.1", path = "../sway-error" } sway-types = { version = "0.42.1", path = "../sway-types" } sway-utils = { version = "0.42.1", path = "../sway-utils" } term-table = "1.3" diff --git a/forc/src/cli/commands/check.rs b/forc/src/cli/commands/check.rs index 58fa976ab77..b86eb8efd9f 100644 --- a/forc/src/cli/commands/check.rs +++ b/forc/src/cli/commands/check.rs @@ -40,7 +40,7 @@ pub struct Command { pub(crate) fn exec(command: Command) -> ForcResult<()> { let engines = Engines::default(); let res = forc_check::check(command, &engines)?; - if !res.is_ok() { + if res.0.is_none() { forc_result_bail!("unable to type check"); } Ok(()) diff --git a/forc/src/ops/forc_check.rs b/forc/src/ops/forc_check.rs index 1623bf0161d..5e8485edac9 100644 --- a/forc/src/ops/forc_check.rs +++ b/forc/src/ops/forc_check.rs @@ -1,11 +1,12 @@ use crate::cli::CheckCommand; use anyhow::Result; -use forc_pkg::{self as pkg}; +use forc_pkg as pkg; use pkg::manifest::ManifestFile; use std::path::PathBuf; -use sway_core::{language::ty, CompileResult, Engines}; +use sway_core::{language::ty, Engines}; +use sway_error::handler::Handler; -pub fn check(command: CheckCommand, engines: &Engines) -> Result> { +pub fn check(command: CheckCommand, engines: &Engines) -> Result<(Option, Handler)> { let CheckCommand { build_target, path, @@ -34,9 +35,9 @@ pub fn check(command: CheckCommand, engines: &Engines) -> Result (Label, Label); - fn compile_function(&mut self, function: Function) -> CompileResult<()>; + fn compile_function( + &mut self, + handler: &Handler, + function: Function, + ) -> Result<(), ErrorEmitted>; fn finalize(&self) -> AsmBuilderResult; } diff --git a/sway-core/src/asm_generation/evm/evm_asm_builder.rs b/sway-core/src/asm_generation/evm/evm_asm_builder.rs index dd01e9dbfea..de3215b3d61 100644 --- a/sway-core/src/asm_generation/evm/evm_asm_builder.rs +++ b/sway-core/src/asm_generation/evm/evm_asm_builder.rs @@ -7,11 +7,13 @@ use crate::{ ProgramKind, }, asm_lang::Label, - error::*, metadata::MetadataManager, }; use etk_ops::london::*; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_ir::{Context, *}; use sway_types::Span; @@ -98,8 +100,12 @@ impl<'ir, 'eng> AsmBuilder for EvmAsmBuilder<'ir, 'eng> { self.func_to_labels(func) } - fn compile_function(&mut self, function: Function) -> CompileResult<()> { - self.compile_function(function) + fn compile_function( + &mut self, + handler: &Handler, + function: Function, + ) -> Result<(), ErrorEmitted> { + self.compile_function(handler, function) } fn finalize(&self) -> AsmBuilderResult { @@ -286,20 +292,14 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { pub(super) fn compile_instruction( &mut self, + handler: &Handler, instr_val: &Value, func_is_entry: bool, - ) -> CompileResult<()> { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); + ) -> Result<(), ErrorEmitted> { if let Some(instruction) = instr_val.get_instruction(self.context) { match instruction { Instruction::AsmBlock(asm, args) => { - check!( - self.compile_asm_block(instr_val, asm, args), - return err(warnings, errors), - warnings, - errors - ) + self.compile_asm_block(handler, instr_val, asm, args)? } Instruction::BitCast(val, ty) => self.compile_bitcast(instr_val, val, ty), Instruction::UnaryOp { op, arg } => self.compile_unary_op(instr_val, op, arg), @@ -316,12 +316,9 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { cond_value, true_block, false_block, - } => check!( - self.compile_conditional_branch(cond_value, true_block, false_block), - return err(warnings, errors), - warnings, - errors - ), + } => { + self.compile_conditional_branch(handler, cond_value, true_block, false_block)? + } Instruction::ContractCall { params, coins, @@ -330,7 +327,7 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { .. } => self.compile_contract_call(instr_val, params, coins, asset_id, gas), Instruction::FuelVm(fuel_vm_instr) => { - errors.push(CompileError::Internal( + handler.emit_err(CompileError::Internal( "Invalid FuelVM IR instruction provided to the EVM code gen.", self.md_mgr .val_to_span(self.context, *instr_val) @@ -344,12 +341,7 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { } => self.compile_get_elem_ptr(instr_val, base, elem_ptr_ty, indices), Instruction::GetLocal(local_var) => self.compile_get_local(instr_val, local_var), Instruction::IntToPtr(val, _) => self.compile_int_to_ptr(instr_val, val), - Instruction::Load(src_val) => check!( - self.compile_load(instr_val, src_val), - return err(warnings, errors), - warnings, - errors - ), + Instruction::Load(src_val) => self.compile_load(handler, instr_val, src_val)?, Instruction::MemCopyBytes { dst_val_ptr, src_val_ptr, @@ -373,30 +365,26 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { Instruction::Store { dst_val_ptr: dst_val, stored_val, - } => check!( - self.compile_store(instr_val, dst_val, stored_val), - return err(warnings, errors), - warnings, - errors - ), + } => self.compile_store(handler, instr_val, dst_val, stored_val)?, } } else { - errors.push(CompileError::Internal( + handler.emit_err(CompileError::Internal( "Value not an instruction.", self.md_mgr .val_to_span(self.context, *instr_val) .unwrap_or_else(Self::empty_span), )); } - ok((), warnings, errors) + Ok(()) } fn compile_asm_block( &mut self, + handler: &Handler, instr_val: &Value, asm: &AsmBlock, asm_args: &[AsmArg], - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -438,10 +426,11 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { fn compile_conditional_branch( &mut self, + handler: &Handler, cond_value: &Value, true_block: &BranchToWithArgs, false_block: &BranchToWithArgs, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -461,7 +450,11 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { todo!(); } - fn compile_get_storage_key(&mut self, instr_val: &Value) -> CompileResult<()> { + fn compile_get_storage_key( + &mut self, + handler: &Handler, + instr_val: &Value, + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -487,7 +480,12 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { todo!(); } - fn compile_load(&mut self, instr_val: &Value, src_val: &Value) -> CompileResult<()> { + fn compile_load( + &mut self, + handler: &Handler, + instr_val: &Value, + src_val: &Value, + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -554,34 +552,42 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { fn compile_state_access_quad_word( &mut self, + handler: &Handler, instr_val: &Value, val: &Value, key: &Value, number_of_slots: &Value, access_type: StateAccessType, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } - fn compile_state_load_word(&mut self, instr_val: &Value, key: &Value) -> CompileResult<()> { + fn compile_state_load_word( + &mut self, + handler: &Handler, + instr_val: &Value, + key: &Value, + ) -> Result<(), ErrorEmitted> { todo!(); } fn compile_state_store_word( &mut self, + handler: &Handler, instr_val: &Value, store_val: &Value, key: &Value, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } fn compile_store( &mut self, + handler: &Handler, instr_val: &Value, dst_val: &Value, stored_val: &Value, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -593,7 +599,11 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { }) } - pub fn compile_function(&mut self, function: Function) -> CompileResult<()> { + pub fn compile_function( + &mut self, + handler: &Handler, + function: Function, + ) -> Result<(), ErrorEmitted> { self.cur_section = Some(EvmAsmSection::new()); // push1 0x80 @@ -623,17 +633,10 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { let func_is_entry = function.is_entry(self.context); // Compile instructions. - let mut warnings = Vec::new(); - let mut errors = Vec::new(); for block in function.block_iter(self.context) { self.insert_block_label(block); for instr_val in block.instruction_iter(self.context) { - check!( - self.compile_instruction(&instr_val, func_is_entry), - return err(warnings, errors), - warnings, - errors - ); + self.compile_instruction(handler, &instr_val, func_is_entry)?; } } @@ -675,7 +678,7 @@ impl<'ir, 'eng> EvmAsmBuilder<'ir, 'eng> { self.sections.push(self.cur_section.take().unwrap()); self.cur_section = None; - ok((), vec![], vec![]) + Ok(()) } pub(super) fn compile_call(&mut self, instr_val: &Value, function: &Function, args: &[Value]) { diff --git a/sway-core/src/asm_generation/finalized_asm.rs b/sway-core/src/asm_generation/finalized_asm.rs index 3cc605f1243..984a3320c1b 100644 --- a/sway-core/src/asm_generation/finalized_asm.rs +++ b/sway-core/src/asm_generation/finalized_asm.rs @@ -6,11 +6,11 @@ use super::{ }; use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode}; use crate::decl_engine::DeclRefFunction; -use crate::error::*; use crate::source_map::SourceMap; use etk_asm::asm::Assembler; use sway_error::error::CompileError; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::span::Span; use sway_types::SourceEngine; @@ -51,39 +51,33 @@ pub struct CompiledBytecode { impl FinalizedAsm { pub(crate) fn to_bytecode_mut( &mut self, + handler: &Handler, source_map: &mut SourceMap, source_engine: &SourceEngine, - ) -> CompileResult { + ) -> Result { match &self.program_section { - InstructionSet::Fuel { ops } => { - to_bytecode_mut(ops, &mut self.data_section, source_map, source_engine) - } + InstructionSet::Fuel { ops } => to_bytecode_mut( + handler, + ops, + &mut self.data_section, + source_map, + source_engine, + ), InstructionSet::Evm { ops } => { let mut assembler = Assembler::new(); if let Err(e) = assembler.push_all(ops.clone()) { - err( - vec![], - vec![CompileError::InternalOwned(e.to_string(), Span::dummy())], - ) + Err(handler.emit_err(CompileError::InternalOwned(e.to_string(), Span::dummy()))) } else { - ok( - CompiledBytecode { - bytecode: assembler.take(), - config_const_offsets: BTreeMap::new(), - }, - vec![], - vec![], - ) + Ok(CompiledBytecode { + bytecode: assembler.take(), + config_const_offsets: BTreeMap::new(), + }) } } - InstructionSet::MidenVM { ops } => ok( - CompiledBytecode { - bytecode: ops.to_bytecode().into(), - config_const_offsets: Default::default(), - }, - vec![], - vec![], - ), + InstructionSet::MidenVM { ops } => Ok(CompiledBytecode { + bytecode: ops.to_bytecode().into(), + config_const_offsets: Default::default(), + }), } } } @@ -104,20 +98,18 @@ impl fmt::Display for FinalizedAsm { } fn to_bytecode_mut( + handler: &Handler, ops: &Vec, data_section: &mut DataSection, source_map: &mut SourceMap, source_engine: &SourceEngine, -) -> CompileResult { - let mut errors = vec![]; - +) -> Result { if ops.len() & 1 != 0 { tracing::info!("ops len: {}", ops.len()); - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "Non-word-aligned (odd-number) ops generated. This is an invariant violation.", Span::new(" ".into(), 0, 0, None).unwrap(), - )); - return err(vec![], errors); + ))); } // The below invariant is introduced to word-align the data section. // A noop is inserted in ASM generation if there is an odd number of ops. @@ -183,27 +175,23 @@ fn to_bytecode_mut( buf.append(&mut data_section); - ok( - CompiledBytecode { - bytecode: buf, - config_const_offsets: config_offsets, - }, - vec![], - errors, - ) + Ok(CompiledBytecode { + bytecode: buf, + config_const_offsets: config_offsets, + }) } /// Checks for disallowed opcodes in non-contract code. /// i.e., if this is a script or predicate, we can't use certain contract opcodes. /// See https://github.com/FuelLabs/sway/issues/350 for details. -pub fn check_invalid_opcodes(asm: &FinalizedAsm) -> CompileResult<()> { +pub fn check_invalid_opcodes(handler: &Handler, asm: &FinalizedAsm) -> Result<(), ErrorEmitted> { match &asm.program_section { InstructionSet::Fuel { ops } => match asm.program_kind { - ProgramKind::Contract | ProgramKind::Library => ok((), vec![], vec![]), - ProgramKind::Script => checks::check_script_opcodes(&ops[..]), - ProgramKind::Predicate => checks::check_predicate_opcodes(&ops[..]), + ProgramKind::Contract | ProgramKind::Library => Ok(()), + ProgramKind::Script => checks::check_script_opcodes(handler, &ops[..]), + ProgramKind::Predicate => checks::check_predicate_opcodes(handler, &ops[..]), }, - InstructionSet::Evm { ops: _ } => ok((), vec![], vec![]), - InstructionSet::MidenVM { ops: _ } => ok((), vec![], vec![]), + InstructionSet::Evm { ops: _ } => Ok(()), + InstructionSet::MidenVM { ops: _ } => Ok(()), } } diff --git a/sway-core/src/asm_generation/from_ir.rs b/sway-core/src/asm_generation/from_ir.rs index b8ec8d3326f..094a052da88 100644 --- a/sway-core/src/asm_generation/from_ir.rs +++ b/sway-core/src/asm_generation/from_ir.rs @@ -11,31 +11,25 @@ use super::{ MidenVMAsmBuilder, }; -use crate::{err, ok, BuildConfig, BuildTarget, CompileResult, CompileWarning}; +use crate::{BuildConfig, BuildTarget}; -use sway_error::error::CompileError; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_ir::*; pub fn compile_ir_to_asm( + handler: &Handler, ir: &Context, build_config: Option<&BuildConfig>, -) -> CompileResult { +) -> Result { // Eventually when we get this 'correct' with no hacks we'll want to compile all the modules // separately and then use a linker to connect them. This way we could also keep binary caches // of libraries and link against them, rather than recompile everything each time. For now we // assume there is one module. assert!(ir.module_iter().count() == 1); - let mut warnings: Vec = Vec::new(); - let mut errors: Vec = Vec::new(); - let module = ir.module_iter().next().unwrap(); - let final_program = check!( - compile_module_to_asm(RegisterSequencer::new(), ir, module, build_config), - return err(warnings, errors), - warnings, - errors - ); + let final_program = + compile_module_to_asm(handler, RegisterSequencer::new(), ir, module, build_config)?; if build_config .map(|cfg| cfg.print_finalized_asm) @@ -47,22 +41,18 @@ pub fn compile_ir_to_asm( let final_asm = final_program.finalize(); - check!( - check_invalid_opcodes(&final_asm), - return err(warnings, errors), - warnings, - errors - ); + check_invalid_opcodes(handler, &final_asm)?; - ok(final_asm, warnings, errors) + Ok(final_asm) } fn compile_module_to_asm( + handler: &Handler, reg_seqr: RegisterSequencer, context: &Context, module: Module, build_config: Option<&BuildConfig>, -) -> CompileResult { +) -> Result { let kind = match module.get_kind(context) { Kind::Contract => ProgramKind::Contract, Kind::Library => ProgramKind::Library, @@ -92,16 +82,8 @@ fn compile_module_to_asm( builder.func_to_labels(&func); } - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - for function in module.function_iter(context) { - check!( - builder.compile_function(function), - return err(warnings, errors), - warnings, - errors - ); + builder.compile_function(handler, function)?; } // Get the compiled result and massage a bit for the AbstractProgram. @@ -135,12 +117,9 @@ fn compile_module_to_asm( println!("{abstract_program}\n"); } - let allocated_program = check!( - CompileResult::from(abstract_program.into_allocated_program()), - return err(warnings, errors), - warnings, - errors - ); + let allocated_program = abstract_program + .into_allocated_program() + .map_err(|e| handler.emit_err(e))?; if build_config .map(|cfg| cfg.print_intermediate_asm) @@ -150,12 +129,9 @@ fn compile_module_to_asm( println!("{allocated_program}"); } - check!( - CompileResult::from(allocated_program.into_final_program()), - return err(warnings, errors), - warnings, - errors - ) + allocated_program + .into_final_program() + .map_err(|e| handler.emit_err(e))? } AsmBuilderResult::Evm(result) => FinalProgram::Evm { ops: result.ops, @@ -164,7 +140,7 @@ fn compile_module_to_asm( AsmBuilderResult::MidenVM(result) => FinalProgram::MidenVM { ops: result.ops }, }; - ok(final_program, warnings, errors) + Ok(final_program) } // ------------------------------------------------------------------------------------------------- diff --git a/sway-core/src/asm_generation/fuel/checks.rs b/sway-core/src/asm_generation/fuel/checks.rs index 7f9b061396b..36c18a0c6d6 100644 --- a/sway-core/src/asm_generation/fuel/checks.rs +++ b/sway-core/src/asm_generation/fuel/checks.rs @@ -1,15 +1,15 @@ //! Various checks and heuristics that are naively run on sequences of opcodes. //! //! This is _not_ the place for optimization passes. -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::Span; -use crate::{ - asm_lang::{ - allocated_ops::{AllocatedOp, AllocatedOpcode}, - VirtualImmediate18, - }, - error::*, +use crate::asm_lang::{ + allocated_ops::{AllocatedOp, AllocatedOpcode}, + VirtualImmediate18, }; /// Checks if an opcode is one that cannot be executed from within a script. @@ -22,41 +22,46 @@ use crate::{ /// } /// } /// ``` -pub(crate) fn check_script_opcodes(ops: &[AllocatedOp]) -> CompileResult<()> { +pub(crate) fn check_script_opcodes( + handler: &Handler, + ops: &[AllocatedOp], +) -> Result<(), ErrorEmitted> { use AllocatedOpcode::*; - let mut errors = vec![]; + let mut error_emitted = None; for op in ops { match op.opcode { GM(_, VirtualImmediate18 { value: 1..=2 }) => { - errors.push(CompileError::GMFromExternalContext { + error_emitted = Some(handler.emit_err(CompileError::GMFromExternalContext { span: get_op_span(op), - }); + })); } MINT(..) => { - errors.push(CompileError::MintFromExternalContext { + error_emitted = Some(handler.emit_err(CompileError::MintFromExternalContext { span: get_op_span(op), - }); + })); } BURN(..) => { - errors.push(CompileError::BurnFromExternalContext { + error_emitted = Some(handler.emit_err(CompileError::BurnFromExternalContext { span: get_op_span(op), - }); + })); } SWW(..) | SRW(..) | SRWQ(..) | SWWQ(..) => { - errors.push(CompileError::ContractStorageFromExternalContext { - span: get_op_span(op), - }); + error_emitted = Some(handler.emit_err( + CompileError::ContractStorageFromExternalContext { + span: get_op_span(op), + }, + )); } _ => (), } } - if errors.is_empty() { - ok((), vec![], errors) - } else { + if let Some(err) = error_emitted { // Abort compilation because the finalized asm contains opcodes invalid to a script. // Preemptively avoids the creation of scripts with opcodes not allowed at runtime. - err(vec![], errors) + Err(err) + } else { + Ok(()) } } @@ -77,55 +82,59 @@ pub(crate) fn check_script_opcodes(ops: &[AllocatedOp]) -> CompileResult<()> { /// the function verifies that the immediate of JI, JNEI, JNZI is greater than the opcode offset. /// /// See: https://fuellabs.github.io/fuel-specs/master/vm/index.html?highlight=predicate#predicate-verification -pub(crate) fn check_predicate_opcodes(ops: &[AllocatedOp]) -> CompileResult<()> { +pub(crate) fn check_predicate_opcodes( + handler: &Handler, + ops: &[AllocatedOp], +) -> Result<(), ErrorEmitted> { use AllocatedOpcode::*; - let mut errors = vec![]; + + let mut error_emitted = None; for op in ops.iter() { - let invalid_opcode = |name_str: &str, errors: &mut Vec| { - errors.push(CompileError::InvalidOpcodeFromPredicate { + let mut invalid_opcode = |name_str: &str| { + error_emitted = Some(handler.emit_err(CompileError::InvalidOpcodeFromPredicate { opcode: name_str.to_string(), span: get_op_span(op), - }); + })); }; match op.opcode.clone() { - BAL(..) => invalid_opcode("BAL", &mut errors), - BHEI(..) => invalid_opcode("BHEI", &mut errors), - BHSH(..) => invalid_opcode("BHSH", &mut errors), - BURN(..) => invalid_opcode("BURN", &mut errors), - CALL(..) => invalid_opcode("CALL", &mut errors), - CB(..) => invalid_opcode("CB", &mut errors), - CCP(..) => invalid_opcode("CCP", &mut errors), - CROO(..) => invalid_opcode("CROO", &mut errors), - CSIZ(..) => invalid_opcode("CSIZ", &mut errors), + BAL(..) => invalid_opcode("BAL"), + BHEI(..) => invalid_opcode("BHEI"), + BHSH(..) => invalid_opcode("BHSH"), + BURN(..) => invalid_opcode("BURN"), + CALL(..) => invalid_opcode("CALL"), + CB(..) => invalid_opcode("CB"), + CCP(..) => invalid_opcode("CCP"), + CROO(..) => invalid_opcode("CROO"), + CSIZ(..) => invalid_opcode("CSIZ"), GM(_, VirtualImmediate18 { value: 1..=2 }) => { - errors.push(CompileError::GMFromExternalContext { + error_emitted = Some(handler.emit_err(CompileError::GMFromExternalContext { span: get_op_span(op), - }); + })); } - LDC(..) => invalid_opcode("LDC", &mut errors), - LOG(..) => invalid_opcode("LOG", &mut errors), - LOGD(..) => invalid_opcode("LOGD", &mut errors), - MINT(..) => invalid_opcode("MINT", &mut errors), - RETD(..) => invalid_opcode("RETD", &mut errors), - SMO(..) => invalid_opcode("SMO", &mut errors), - SRW(..) => invalid_opcode("SRW", &mut errors), - SRWQ(..) => invalid_opcode("SRWQ", &mut errors), - SWW(..) => invalid_opcode("SWW", &mut errors), - SWWQ(..) => invalid_opcode("SWWQ", &mut errors), - TIME(..) => invalid_opcode("TIME", &mut errors), - TR(..) => invalid_opcode("TR", &mut errors), - TRO(..) => invalid_opcode("TRO", &mut errors), + LDC(..) => invalid_opcode("LDC"), + LOG(..) => invalid_opcode("LOG"), + LOGD(..) => invalid_opcode("LOGD"), + MINT(..) => invalid_opcode("MINT"), + RETD(..) => invalid_opcode("RETD"), + SMO(..) => invalid_opcode("SMO"), + SRW(..) => invalid_opcode("SRW"), + SRWQ(..) => invalid_opcode("SRWQ"), + SWW(..) => invalid_opcode("SWW"), + SWWQ(..) => invalid_opcode("SWWQ"), + TIME(..) => invalid_opcode("TIME"), + TR(..) => invalid_opcode("TR"), + TRO(..) => invalid_opcode("TRO"), _ => (), }; } - if errors.is_empty() { - ok((), vec![], errors) - } else { + if let Some(err) = error_emitted { // Abort compilation because the finalized asm contains opcodes invalid to a predicate. // Preemptively avoids the creation of predicates with opcodes not allowed at runtime. - err(vec![], errors) + Err(err) + } else { + Ok(()) } } diff --git a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs index e848a08f5b9..eaa2cb64fbd 100644 --- a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs +++ b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs @@ -12,11 +12,15 @@ use crate::{ }, asm_lang::{virtual_register::*, Label, Op, VirtualImmediate12, VirtualImmediate18, VirtualOp}, decl_engine::DeclRefFunction, - error::*, metadata::MetadataManager, }; -use sway_error::{error::CompileError, warning::CompileWarning, warning::Warning}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, + warning::CompileWarning, + warning::Warning, +}; use sway_ir::*; use sway_types::{span::Span, Spanned}; @@ -83,8 +87,12 @@ impl<'ir, 'eng> AsmBuilder for FuelAsmBuilder<'ir, 'eng> { self.func_to_labels(func) } - fn compile_function(&mut self, function: Function) -> CompileResult<()> { - self.compile_function(function) + fn compile_function( + &mut self, + handler: &Handler, + function: Function, + ) -> Result<(), ErrorEmitted> { + self.compile_function(handler, function) } fn finalize(&self) -> AsmBuilderResult { @@ -138,26 +146,23 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { pub(super) fn compile_instruction( &mut self, + handler: &Handler, instr_val: &Value, func_is_entry: bool, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { let Some(instruction) = instr_val.get_instruction(self.context) else { - return err( - vec![], - vec![CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "Value not an instruction.", self.md_mgr .val_to_span(self.context, *instr_val) - .unwrap_or_else(Span::dummy), - )], - ); + .unwrap_or_else(Span::dummy), ))); }; - // The only instruction whose compilation returns a CompileResult itself is AsmBlock, which + // The only instruction whose compilation returns a Result itself is AsmBlock, which // we special-case here. Ideally, the ASM block verification would happen much sooner, // perhaps during parsing. https://github.com/FuelLabs/sway/issues/801 if let Instruction::AsmBlock(asm, args) = instruction { - self.compile_asm_block(instr_val, asm, args) + self.compile_asm_block(handler, instr_val, asm, args) } else { // These matches all return `Result<(), CompileError>`. match instruction { @@ -273,36 +278,35 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { stored_val, } => self.compile_store(instr_val, dst_val_ptr, stored_val), } - .into() + .map_err(|e| handler.emit_err(e)) } } fn compile_asm_block( &mut self, + handler: &Handler, instr_val: &Value, asm: &AsmBlock, asm_args: &[AsmArg], - ) -> CompileResult<()> { - let mut warnings: Vec = Vec::new(); - let mut errors: Vec = Vec::new(); + ) -> Result<(), ErrorEmitted> { let mut inline_reg_map = HashMap::new(); let mut inline_ops = Vec::new(); for AsmArg { name, initializer } in asm_args { - assert_or_warn!( - ConstantRegister::parse_register_name(name.as_str()).is_none(), - warnings, - name.span().clone(), - Warning::ShadowingReservedRegister { - reg_name: name.clone() - } - ); + if ConstantRegister::parse_register_name(name.as_str()).is_some() { + handler.emit_warn(CompileWarning { + span: name.span().clone(), + warning_content: Warning::ShadowingReservedRegister { + reg_name: name.clone(), + }, + }); + } + let arg_reg = match initializer { Some(init_val) => { let init_val_reg = match self.value_to_register(init_val) { Ok(ivr) => ivr, Err(e) => { - errors.push(e); - return err(warnings, errors); + return Err(handler.emit_err(e)); } }; match init_val_reg { @@ -353,7 +357,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { }) .filter_map(|res| match res { Err(e) => { - errors.push(e); + handler.emit_err(e); None } Ok(o) => Some(o), @@ -365,17 +369,13 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { .md_mgr .md_to_span(self.context, op.metadata) .unwrap_or_else(Span::dummy); - let opcode = check!( - Op::parse_opcode( - &op.name, - &replaced_registers, - &op.immediate, - op_span.clone(), - ), - return err(warnings, errors), - warnings, - errors - ); + let opcode = Op::parse_opcode( + handler, + &op.name, + &replaced_registers, + &op.immediate, + op_span.clone(), + )?; inline_ops.push(Op { opcode: either::Either::Left(opcode), @@ -391,15 +391,14 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { let ret_reg = match realize_register(ret_reg_name.as_str()) { Some(reg) => reg, None => { - errors.push(CompileError::UnknownRegister { + return Err(handler.emit_err(CompileError::UnknownRegister { initialized_registers: inline_reg_map .keys() .map(|name| name.to_string()) .collect::>() .join("\n"), span: ret_reg_name.span(), - }); - return err(warnings, errors); + })); } }; let instr_reg = self.reg_seqr.next(); @@ -413,7 +412,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { self.cur_bytecode.append(&mut inline_ops); - ok((), warnings, errors) + Ok(()) } fn compile_bitcast( diff --git a/sway-core/src/asm_generation/fuel/functions.rs b/sway-core/src/asm_generation/fuel/functions.rs index 14f63e5f741..ab2ee411902 100644 --- a/sway-core/src/asm_generation/fuel/functions.rs +++ b/sway-core/src/asm_generation/fuel/functions.rs @@ -10,7 +10,6 @@ use crate::{ VirtualOp, }, decl_engine::DeclRef, - error::*, fuel_prelude::fuel_asm::GTFArgs, size_bytes_in_words, size_bytes_round_up_to_word_alignment, }; @@ -18,7 +17,10 @@ use crate::{ use sway_ir::*; use either::Either; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::Ident; use super::data_section::DataId; @@ -140,7 +142,11 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { Ok(()) } - pub fn compile_function(&mut self, function: Function) -> CompileResult<()> { + pub fn compile_function( + &mut self, + handler: &Handler, + function: Function, + ) -> Result<(), ErrorEmitted> { assert!( self.cur_bytecode.is_empty(), "can't do nested functions yet" @@ -194,14 +200,11 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { }); } - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let locals_alloc_result = self.alloc_locals(function); if func_is_entry { - let result = Into::>::into(self.compile_external_args(function)); - check!(result, return err(warnings, errors), warnings, errors); + self.compile_external_args(function) + .map_err(|e| handler.emit_err(e))? } else { // Make copies of the arg registers. self.compile_fn_call_args(function) @@ -238,12 +241,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { self.cur_bytecode.push(Op::unowned_jump_label(label)); for instr_val in block.instruction_iter(self.context) { - check!( - self.compile_instruction(&instr_val, func_is_entry), - return err(warnings, errors), - warnings, - errors - ); + self.compile_instruction(handler, &instr_val, func_is_entry)?; } } @@ -291,7 +289,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { self.non_entries.push(ops); } - ok((), warnings, errors) + Ok(()) } fn compile_fn_call_args(&mut self, function: Function) { diff --git a/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs b/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs index 7efd3a23480..b4ae572e713 100644 --- a/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs +++ b/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs @@ -11,11 +11,13 @@ use crate::{ ProgramKind, }, asm_lang::Label, - error::*, metadata::MetadataManager, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_ir::{Context, *}; use sway_types::Span; @@ -115,8 +117,12 @@ pub struct MidenVMAsmBuilderResult { pub type MidenVMAbiResult = (); impl<'ir, 'eng> AsmBuilder for MidenVMAsmBuilder<'ir, 'eng> { - fn compile_function(&mut self, function: Function) -> CompileResult<()> { - self.compile_function(function) + fn compile_function( + &mut self, + handler: &Handler, + function: Function, + ) -> Result<(), ErrorEmitted> { + self.compile_function(handler, function) } fn finalize(&self) -> AsmBuilderResult { @@ -215,7 +221,11 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { } /// compiles some value and ensures it is on the top of the stack - fn push_value_to_stack(&mut self, value: &Value) -> CompileResult<()> { + fn push_value_to_stack( + &mut self, + handler: &Handler, + value: &Value, + ) -> Result<(), ErrorEmitted> { todo!() } @@ -226,6 +236,7 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { fn compile_conditional_branch( &mut self, + handler: &Handler, cond_value: &Value, true_block: &BranchToWithArgs, false_block: &BranchToWithArgs, @@ -235,7 +246,7 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { // generate the body // generate the `else` // generate the else block - self.push_value_to_stack(cond_value); + let _ = self.push_value_to_stack(handler, cond_value); self.compile_branch(true_block); self.compile_branch(true_block); // todo need to figure out how to handle the compile results here @@ -270,7 +281,7 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { function.get_name(self.context) ) } - pub(super) fn compile_instruction(&mut self, instr_val: &Value) { + pub(super) fn compile_instruction(&mut self, handler: &Handler, instr_val: &Value) { if let Some(instruction) = instr_val.get_instruction(self.context) { match instruction { Instruction::AsmBlock(asm, args) => todo!(), @@ -293,7 +304,7 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { cond_value, true_block, false_block, - } => self.compile_conditional_branch(cond_value, true_block, false_block), + } => self.compile_conditional_branch(handler, cond_value, true_block, false_block), Instruction::ContractCall { params, coins, @@ -342,10 +353,11 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { fn compile_asm_block( &mut self, + handler: &Handler, instr_val: &Value, asm: &AsmBlock, asm_args: &[AsmArg], - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -411,7 +423,11 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { todo!(); } - fn compile_get_storage_key(&mut self, instr_val: &Value) -> CompileResult<()> { + fn compile_get_storage_key( + &mut self, + handler: &Handler, + instr_val: &Value, + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -448,7 +464,12 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { todo!(); } - fn compile_load(&mut self, instr_val: &Value, src_val: &Value) -> CompileResult<()> { + fn compile_load( + &mut self, + handler: &Handler, + instr_val: &Value, + src_val: &Value, + ) -> Result<(), ErrorEmitted> { todo!(); } @@ -491,50 +512,62 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { fn compile_state_access_quad_word( &mut self, + handler: &Handler, instr_val: &Value, val: &Value, key: &Value, number_of_slots: &Value, access_type: StateAccessType, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } - fn compile_state_load_word(&mut self, instr_val: &Value, key: &Value) -> CompileResult<()> { + fn compile_state_load_word( + &mut self, + handler: &Handler, + instr_val: &Value, + key: &Value, + ) -> Result<(), ErrorEmitted> { todo!(); } fn compile_state_store_word( &mut self, + handler: &Handler, instr_val: &Value, store_val: &Value, key: &Value, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } fn compile_store( &mut self, + handler: &Handler, instr_val: &Value, dst_val: &Value, stored_val: &Value, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { todo!(); } - pub fn compile_function(&mut self, function: Function) -> CompileResult<()> { + pub fn compile_function( + &mut self, + handler: &Handler, + function: Function, + ) -> Result<(), ErrorEmitted> { if function.get_name(self.context).to_lowercase() != "main" { self.set_active_procedure(&function); } - self.compile_code_block(function.block_iter(self.context)); + self.compile_code_block(handler, function.block_iter(self.context)); self.end_active_procedure(); - ok((), vec![], vec![]) + Ok(()) } - fn compile_code_block(&mut self, block: BlockIterator) { + fn compile_code_block(&mut self, handler: &Handler, block: BlockIterator) { for block in block { for instr_val in block.instruction_iter(self.context) { - self.compile_instruction(&instr_val); + self.compile_instruction(handler, &instr_val); } } } diff --git a/sway-core/src/asm_lang/mod.rs b/sway-core/src/asm_lang/mod.rs index 9f544cff6ac..75f71486a20 100644 --- a/sway-core/src/asm_lang/mod.rs +++ b/sway-core/src/asm_lang/mod.rs @@ -16,12 +16,14 @@ pub(crate) use virtual_register::*; use crate::{ asm_generation::fuel::{data_section::DataId, register_allocator::RegisterPool}, asm_lang::allocated_ops::{AllocatedOpcode, AllocatedRegister}, - error::*, language::AsmRegister, Ident, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{span::Span, Spanned}; use either::Either; @@ -260,752 +262,351 @@ impl Op { } pub(crate) fn parse_opcode( + handler: &Handler, name: &Ident, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - ok( - match name.as_str() { - /* Arithmetic/Logic (ALU) Instructions */ - "add" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::ADD(r1, r2, r3) - } - "addi" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::ADDI(r1, r2, imm) - } - "and" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::AND(r1, r2, r3) - } - "andi" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::ANDI(r1, r2, imm) - } - "div" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::DIV(r1, r2, r3) - } - "divi" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::DIVI(r1, r2, imm) - } - "eq" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::EQ(r1, r2, r3) - } - "exp" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::EXP(r1, r2, r3) - } - "expi" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::EXPI(r1, r2, imm) - } - "gt" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::GT(r1, r2, r3) - } - "lt" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::LT(r1, r2, r3) - } - "mlog" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MLOG(r1, r2, r3) - } - "mod" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MOD(r1, r2, r3) - } - "modi" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MODI(r1, r2, imm) - } - "move" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MOVE(r1, r2) - } - "movi" => { - let (r1, imm) = check!( - single_reg_imm_18(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MOVI(r1, imm) - } - "mroo" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MROO(r1, r2, r3) - } - "mul" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MUL(r1, r2, r3) - } - "muli" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MULI(r1, r2, imm) - } - "noop" => VirtualOp::NOOP, - "not" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::NOT(r1, r2) - } - "or" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::OR(r1, r2, r3) - } - "ori" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::ORI(r1, r2, imm) - } - "sll" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SLL(r1, r2, r3) - } - "slli" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SLLI(r1, r2, imm) - } - "srl" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SRL(r1, r2, r3) - } - "srli" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SRLI(r1, r2, imm) - } - "sub" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SUB(r1, r2, r3) - } - "subi" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SUBI(r1, r2, imm) - } - "xor" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::XOR(r1, r2, r3) - } - "xori" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::XORI(r1, r2, imm) - } + ) -> Result { + Ok(match name.as_str() { + /* Arithmetic/Logic (ALU) Instructions */ + "add" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::ADD(r1, r2, r3) + } + "addi" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::ADDI(r1, r2, imm) + } + "and" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::AND(r1, r2, r3) + } + "andi" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::ANDI(r1, r2, imm) + } + "div" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::DIV(r1, r2, r3) + } + "divi" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::DIVI(r1, r2, imm) + } + "eq" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::EQ(r1, r2, r3) + } + "exp" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::EXP(r1, r2, r3) + } + "expi" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::EXPI(r1, r2, imm) + } + "gt" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::GT(r1, r2, r3) + } + "lt" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::LT(r1, r2, r3) + } + "mlog" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MLOG(r1, r2, r3) + } + "mod" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MOD(r1, r2, r3) + } + "modi" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::MODI(r1, r2, imm) + } + "move" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MOVE(r1, r2) + } + "movi" => { + let (r1, imm) = single_reg_imm_18(handler, args, immediate, whole_op_span)?; + VirtualOp::MOVI(r1, imm) + } + "mroo" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MROO(r1, r2, r3) + } + "mul" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MUL(r1, r2, r3) + } + "muli" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::MULI(r1, r2, imm) + } + "noop" => VirtualOp::NOOP, + "not" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::NOT(r1, r2) + } + "or" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::OR(r1, r2, r3) + } + "ori" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::ORI(r1, r2, imm) + } + "sll" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SLL(r1, r2, r3) + } + "slli" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::SLLI(r1, r2, imm) + } + "srl" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SRL(r1, r2, r3) + } + "srli" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::SRLI(r1, r2, imm) + } + "sub" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SUB(r1, r2, r3) + } + "subi" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::SUBI(r1, r2, imm) + } + "xor" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::XOR(r1, r2, r3) + } + "xori" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::XORI(r1, r2, imm) + } - /* Control Flow Instructions */ - "jmp" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::JMP(r1) - } - "ji" => { - let imm = check!( - single_imm_24(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::JI(imm) - } - "jne" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::JNE(r1, r2, r3) - } - "jnei" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::JNEI(r1, r2, imm) - } - "jnzi" => { - let (r1, imm) = check!( - single_reg_imm_18(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::JNZI(r1, imm) - } - "ret" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::RET(r1) - } + /* Control Flow Instructions */ + "jmp" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::JMP(r1) + } + "ji" => { + let imm = single_imm_24(handler, args, immediate, whole_op_span)?; + VirtualOp::JI(imm) + } + "jne" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::JNE(r1, r2, r3) + } + "jnei" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::JNEI(r1, r2, imm) + } + "jnzi" => { + let (r1, imm) = single_reg_imm_18(handler, args, immediate, whole_op_span)?; + VirtualOp::JNZI(r1, imm) + } + "ret" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::RET(r1) + } - /* Memory Instructions */ - "aloc" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::ALOC(r1) - } - "cfei" => { - let imm = check!( - single_imm_24(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::CFEI(imm) - } - "cfsi" => { - let imm = check!( - single_imm_24(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::CFSI(imm) - } - "lb" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::LB(r1, r2, imm) - } - "lw" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::LW(r1, r2, imm) - } - "mcl" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MCL(r1, r2) - } - "mcli" => { - let (r1, imm) = check!( - single_reg_imm_18(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MCLI(r1, imm) - } - "mcp" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MCP(r1, r2, r3) - } - "mcpi" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MCPI(r1, r2, imm) - } - "meq" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MEQ(r1, r2, r3, r4) - } - "sb" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SB(r1, r2, imm) - } - "sw" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SW(r1, r2, imm) - } + /* Memory Instructions */ + "aloc" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::ALOC(r1) + } + "cfei" => { + let imm = single_imm_24(handler, args, immediate, whole_op_span)?; + VirtualOp::CFEI(imm) + } + "cfsi" => { + let imm = single_imm_24(handler, args, immediate, whole_op_span)?; + VirtualOp::CFSI(imm) + } + "lb" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::LB(r1, r2, imm) + } + "lw" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::LW(r1, r2, imm) + } + "mcl" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MCL(r1, r2) + } + "mcli" => { + let (r1, imm) = single_reg_imm_18(handler, args, immediate, whole_op_span)?; + VirtualOp::MCLI(r1, imm) + } + "mcp" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MCP(r1, r2, r3) + } + "mcpi" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::MCPI(r1, r2, imm) + } + "meq" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::MEQ(r1, r2, r3, r4) + } + "sb" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::SB(r1, r2, imm) + } + "sw" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::SW(r1, r2, imm) + } - /* Contract Instructions */ - "bal" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::BAL(r1, r2, r3) - } - "bhei" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::BHEI(r1) - } - "bhsh" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::BHSH(r1, r2) - } - "burn" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::BURN(r1) - } - "call" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::CALL(r1, r2, r3, r4) - } - "cb" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::CB(r1) - } - "ccp" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::CCP(r1, r2, r3, r4) - } - "croo" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::CROO(r1, r2) - } - "csiz" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::CSIZ(r1, r2) - } + /* Contract Instructions */ + "bal" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::BAL(r1, r2, r3) + } + "bhei" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::BHEI(r1) + } + "bhsh" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::BHSH(r1, r2) + } + "burn" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::BURN(r1) + } + "call" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::CALL(r1, r2, r3, r4) + } + "cb" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::CB(r1) + } + "ccp" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::CCP(r1, r2, r3, r4) + } + "croo" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::CROO(r1, r2) + } + "csiz" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::CSIZ(r1, r2) + } - "ldc" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::LDC(r1, r2, r3) - } - "log" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::LOG(r1, r2, r3, r4) - } - "logd" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::LOGD(r1, r2, r3, r4) - } - "mint" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::MINT(r1) - } - "retd" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::RETD(r1, r2) - } - "rvrt" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::RVRT(r1) - } - "smo" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SMO(r1, r2, r3, r4) - } - "scwq" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SCWQ(r1, r2, r3) - } - "srw" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SRW(r1, r2, r3) - } - "srwq" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SRWQ(r1, r2, r3, r4) - } - "sww" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SWW(r1, r2, r3) - } - "swwq" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::SWWQ(r1, r2, r3, r4) - } - "time" => { - let (r1, r2) = check!( - two_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::TIME(r1, r2) - } - "tr" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::TR(r1, r2, r3) - } - "tro" => { - let (r1, r2, r3, r4) = check!( - four_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::TRO(r1, r2, r3, r4) - } + "ldc" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::LDC(r1, r2, r3) + } + "log" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::LOG(r1, r2, r3, r4) + } + "logd" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::LOGD(r1, r2, r3, r4) + } + "mint" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::MINT(r1) + } + "retd" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::RETD(r1, r2) + } + "rvrt" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::RVRT(r1) + } + "smo" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SMO(r1, r2, r3, r4) + } + "scwq" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SCWQ(r1, r2, r3) + } + "srw" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SRW(r1, r2, r3) + } + "srwq" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SRWQ(r1, r2, r3, r4) + } + "sww" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SWW(r1, r2, r3) + } + "swwq" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::SWWQ(r1, r2, r3, r4) + } + "time" => { + let (r1, r2) = two_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::TIME(r1, r2) + } + "tr" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::TR(r1, r2, r3) + } + "tro" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::TRO(r1, r2, r3, r4) + } - /* Cryptographic Instructions */ - "ecr" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::ECR(r1, r2, r3) - } - "k256" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::K256(r1, r2, r3) - } - "s256" => { - let (r1, r2, r3) = check!( - three_regs(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::S256(r1, r2, r3) - } + /* Cryptographic Instructions */ + "ecr" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::ECR(r1, r2, r3) + } + "k256" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::K256(r1, r2, r3) + } + "s256" => { + let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::S256(r1, r2, r3) + } - /* Other Instructions */ - "flag" => { - let r1 = check!( - single_reg(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::FLAG(r1) - } - "gm" => { - let (r1, imm) = check!( - single_reg_imm_18(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::GM(r1, imm) - } - "gtf" => { - let (r1, r2, imm) = check!( - two_regs_imm_12(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::GTF(r1, r2, imm) - } + /* Other Instructions */ + "flag" => { + let r1 = single_reg(handler, args, immediate, whole_op_span)?; + VirtualOp::FLAG(r1) + } + "gm" => { + let (r1, imm) = single_reg_imm_18(handler, args, immediate, whole_op_span)?; + VirtualOp::GM(r1, imm) + } + "gtf" => { + let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; + VirtualOp::GTF(r1, r2, imm) + } - /* Non-VM Instructions */ - "blob" => { - let imm = check!( - single_imm_24(args, immediate, whole_op_span), - return err(warnings, errors), - warnings, - errors - ); - VirtualOp::BLOB(imm) - } - _ => { - errors.push(CompileError::UnrecognizedOp { - op_name: name.clone(), - span: name.span(), - }); - return err(warnings, errors); - } - }, - warnings, - errors, - ) + /* Non-VM Instructions */ + "blob" => { + let imm = single_imm_24(handler, args, immediate, whole_op_span)?; + VirtualOp::BLOB(imm) + } + _ => { + return Err(handler.emit_err(CompileError::UnrecognizedOp { + op_name: name.clone(), + span: name.span(), + })); + } + }) } pub(crate) fn registers(&self) -> BTreeSet<&VirtualRegister> { @@ -1067,14 +668,13 @@ impl Op { } fn single_reg( + handler: &Handler, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, -) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result { if args.len() > 1 { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { expected: 1, received: args.len(), span: whole_op_span.clone(), @@ -1084,33 +684,33 @@ fn single_reg( let reg = match args.get(0) { Some(reg) => reg, _ => { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { - span: whole_op_span, - expected: 1, - received: args.len(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { + span: whole_op_span, + expected: 1, + received: args.len(), + }), + ); } }; match immediate { None => (), Some(i) => { - errors.push(CompileError::UnnecessaryImmediate { span: i.span() }); + handler.emit_err(CompileError::UnnecessaryImmediate { span: i.span() }); } }; - ok(reg.clone(), warnings, errors) + Ok(reg.clone()) } fn two_regs( + handler: &Handler, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, -) -> CompileResult<(VirtualRegister, VirtualRegister)> { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result<(VirtualRegister, VirtualRegister), ErrorEmitted> { if args.len() > 2 { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { span: whole_op_span.clone(), expected: 2, received: args.len(), @@ -1120,36 +720,41 @@ fn two_regs( let (reg, reg2) = match (args.get(0), args.get(1)) { (Some(reg), Some(reg2)) => (reg, reg2), _ => { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { - span: whole_op_span, - expected: 2, - received: args.len(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { + span: whole_op_span, + expected: 2, + received: args.len(), + }), + ); } }; match immediate { None => (), - Some(i) => errors.push(CompileError::UnnecessaryImmediate { span: i.span() }), + Some(i) => { + handler.emit_err(CompileError::UnnecessaryImmediate { span: i.span() }); + } }; - ok((reg.clone(), reg2.clone()), warnings, errors) + Ok((reg.clone(), reg2.clone())) } fn four_regs( + handler: &Handler, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, -) -> CompileResult<( - VirtualRegister, - VirtualRegister, - VirtualRegister, - VirtualRegister, -)> { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result< + ( + VirtualRegister, + VirtualRegister, + VirtualRegister, + VirtualRegister, + ), + ErrorEmitted, +> { if args.len() > 4 { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { span: whole_op_span.clone(), expected: 4, received: args.len(), @@ -1159,18 +764,19 @@ fn four_regs( let (reg, reg2, reg3, reg4) = match (args.get(0), args.get(1), args.get(2), args.get(3)) { (Some(reg), Some(reg2), Some(reg3), Some(reg4)) => (reg, reg2, reg3, reg4), _ => { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { - span: whole_op_span, - expected: 4, - received: args.len(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { + span: whole_op_span, + expected: 4, + received: args.len(), + }), + ); } }; match immediate { None => (), Some(i) => { - errors.push(CompileError::MissingImmediate { span: i.span() }); + handler.emit_err(CompileError::MissingImmediate { span: i.span() }); } }; @@ -1203,22 +809,17 @@ fn four_regs( // Immediate Value. pub type ImmediateValue = u32; - ok( - (reg.clone(), reg2.clone(), reg3.clone(), reg4.clone()), - warnings, - errors, - ) + Ok((reg.clone(), reg2.clone(), reg3.clone(), reg4.clone())) } fn three_regs( + handler: &Handler, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, -) -> CompileResult<(VirtualRegister, VirtualRegister, VirtualRegister)> { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result<(VirtualRegister, VirtualRegister, VirtualRegister), ErrorEmitted> { if args.len() > 3 { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { span: whole_op_span.clone(), expected: 3, received: args.len(), @@ -1228,32 +829,32 @@ fn three_regs( let (reg, reg2, reg3) = match (args.get(0), args.get(1), args.get(2)) { (Some(reg), Some(reg2), Some(reg3)) => (reg, reg2, reg3), _ => { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { - span: whole_op_span, - expected: 3, - received: args.len(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { + span: whole_op_span, + expected: 3, + received: args.len(), + }), + ); } }; match immediate { None => (), Some(i) => { - errors.push(CompileError::UnnecessaryImmediate { span: i.span() }); + handler.emit_err(CompileError::UnnecessaryImmediate { span: i.span() }); } }; - ok((reg.clone(), reg2.clone(), reg3.clone()), warnings, errors) + Ok((reg.clone(), reg2.clone(), reg3.clone())) } fn single_imm_24( + handler: &Handler, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, -) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result { if !args.is_empty() { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { span: whole_op_span.clone(), expected: 0, received: args.len(), @@ -1261,16 +862,16 @@ fn single_imm_24( } let (imm, imm_span): (u64, _) = match immediate { None => { - errors.push(CompileError::MissingImmediate { + return Err(handler.emit_err(CompileError::MissingImmediate { span: whole_op_span, - }); - return err(warnings, errors); + })); } Some(i) => match i.as_str()[1..].parse() { Ok(o) => (o, i.span()), Err(_) => { - errors.push(CompileError::InvalidImmediateValue { span: i.span() }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::InvalidImmediateValue { span: i.span() }) + ); } }, }; @@ -1278,22 +879,20 @@ fn single_imm_24( let imm = match VirtualImmediate24::new(imm, imm_span) { Ok(o) => o, Err(e) => { - errors.push(e); - return err(warnings, errors); + return Err(handler.emit_err(e)); } }; - ok(imm, warnings, errors) + Ok(imm) } fn single_reg_imm_18( + handler: &Handler, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, -) -> CompileResult<(VirtualRegister, VirtualImmediate18)> { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result<(VirtualRegister, VirtualImmediate18), ErrorEmitted> { if args.len() > 1 { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { span: whole_op_span.clone(), expected: 1, received: args.len(), @@ -1302,26 +901,27 @@ fn single_reg_imm_18( let reg = match args.get(0) { Some(reg) => reg, _ => { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { - span: whole_op_span, - expected: 1, - received: args.len(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { + span: whole_op_span, + expected: 1, + received: args.len(), + }), + ); } }; let (imm, imm_span): (u64, _) = match immediate { None => { - errors.push(CompileError::MissingImmediate { + return Err(handler.emit_err(CompileError::MissingImmediate { span: whole_op_span, - }); - return err(warnings, errors); + })); } Some(i) => match i.as_str()[1..].parse() { Ok(o) => (o, i.span()), Err(_) => { - errors.push(CompileError::InvalidImmediateValue { span: i.span() }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::InvalidImmediateValue { span: i.span() }) + ); } }, }; @@ -1329,22 +929,20 @@ fn single_reg_imm_18( let imm = match VirtualImmediate18::new(imm, imm_span) { Ok(o) => o, Err(e) => { - errors.push(e); - return err(warnings, errors); + return Err(handler.emit_err(e)); } }; - ok((reg.clone(), imm), warnings, errors) + Ok((reg.clone(), imm)) } fn two_regs_imm_12( + handler: &Handler, args: &[VirtualRegister], immediate: &Option, whole_op_span: Span, -) -> CompileResult<(VirtualRegister, VirtualRegister, VirtualImmediate12)> { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result<(VirtualRegister, VirtualRegister, VirtualImmediate12), ErrorEmitted> { if args.len() > 2 { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { span: whole_op_span.clone(), expected: 2, received: args.len(), @@ -1353,26 +951,27 @@ fn two_regs_imm_12( let (reg, reg2) = match (args.get(0), args.get(1)) { (Some(reg), Some(reg2)) => (reg, reg2), _ => { - errors.push(CompileError::IncorrectNumberOfAsmRegisters { - span: whole_op_span, - expected: 2, - received: args.len(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::IncorrectNumberOfAsmRegisters { + span: whole_op_span, + expected: 2, + received: args.len(), + }), + ); } }; let (imm, imm_span): (u64, _) = match immediate { None => { - errors.push(CompileError::MissingImmediate { + return Err(handler.emit_err(CompileError::MissingImmediate { span: whole_op_span, - }); - return err(warnings, errors); + })); } Some(i) => match i.as_str()[1..].parse() { Ok(o) => (o, i.span()), Err(_) => { - errors.push(CompileError::InvalidImmediateValue { span: i.span() }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::InvalidImmediateValue { span: i.span() }) + ); } }, }; @@ -1380,12 +979,11 @@ fn two_regs_imm_12( let imm = match VirtualImmediate12::new(imm, imm_span) { Ok(o) => o, Err(e) => { - errors.push(e); - return err(warnings, errors); + return Err(handler.emit_err(e)); } }; - ok((reg.clone(), reg2.clone(), imm), warnings, errors) + Ok((reg.clone(), reg2.clone(), imm)) } impl fmt::Display for Op { diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index 367e119a5e0..ffdc94bc8f6 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -12,8 +12,11 @@ use crate::{ }; use petgraph::{prelude::NodeIndex, visit::Dfs}; use std::collections::{BTreeSet, HashMap}; -use sway_error::warning::{CompileWarning, Warning}; use sway_error::{error::CompileError, type_error::TypeError}; +use sway_error::{ + handler::Handler, + warning::{CompileWarning, Warning}, +}; use sway_types::{constants::ALLOW_DEAD_CODE_NAME, span::Span, Ident, Named, Spanned}; impl<'cfg> ControlFlowGraph<'cfg> { @@ -1488,8 +1491,8 @@ fn connect_expression<'eng: 'cfg, 'cfg>( .unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())); let resolved_type_of_parent = match resolved_type_of_parent - .expect_struct(engines, field_instantiation_span) - .value + .expect_struct(&Handler::default(), engines, field_instantiation_span) + .ok() { Some(struct_decl_ref) => decl_engine.get_struct(&struct_decl_ref).call_path, None => { diff --git a/sway-core/src/error.rs b/sway-core/src/error.rs index 4eb78478d1e..d716b13945a 100644 --- a/sway-core/src/error.rs +++ b/sway-core/src/error.rs @@ -1,64 +1,6 @@ //! Tools related to handling/recovering from Sway compile errors and reporting them to the user. use crate::language::parsed::VariableDeclaration; -use sway_error::error::CompileError; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_error::warning::CompileWarning; - -macro_rules! check { - ($fn_expr: expr, $error_recovery: expr, $warnings: ident, $errors: ident $(,)?) => {{ - let mut res = $fn_expr; - $warnings.append(&mut res.warnings); - $errors.append(&mut res.errors); - #[allow(clippy::manual_unwrap_or)] - match res.value { - None => $error_recovery, - Some(value) => value, - } - }}; -} - -macro_rules! append { - ($fn_expr: expr, $warnings: ident, $errors: ident $(,)?) => {{ - let (mut l, mut r) = $fn_expr; - $warnings.append(&mut l); - $errors.append(&mut r); - }}; -} - -macro_rules! assert_or_warn { - ($bool_expr: expr, $warnings: ident, $span: expr, $warning: expr $(,)?) => {{ - if !$bool_expr { - use sway_error::warning::CompileWarning; - $warnings.push(CompileWarning { - warning_content: $warning, - span: $span, - }); - } - }}; -} - -/// Denotes a non-recoverable state -pub(crate) fn err(warnings: Vec, errors: Vec) -> CompileResult { - CompileResult { - value: None, - warnings, - errors, - } -} - -/// Denotes a recovered or non-error state -pub(crate) fn ok( - value: T, - warnings: Vec, - errors: Vec, -) -> CompileResult { - CompileResult { - value: Some(value), - warnings, - errors, - } -} /// Acts as the result of parsing `Declaration`s, `Expression`s, etc. /// Some `Expression`s need to be able to create `VariableDeclaration`s, @@ -79,140 +21,3 @@ impl ParserLifter { } } } - -#[derive(Debug, Clone)] -pub struct CompileResult { - pub value: Option, - pub warnings: Vec, - pub errors: Vec, -} - -impl From> for CompileResult { - fn from(o: Result) -> Self { - match o { - Ok(o) => CompileResult { - value: Some(o), - warnings: vec![], - errors: vec![], - }, - Err(e) => CompileResult { - value: None, - warnings: vec![], - errors: vec![e], - }, - } - } -} - -impl From<(Vec, Vec)> for CompileResult<()> { - fn from(o: (Vec, Vec)) -> Self { - let (warnings, errors) = o; - if errors.is_empty() { - CompileResult { - value: Some(()), - warnings, - errors, - } - } else { - CompileResult { - value: None, - warnings, - errors, - } - } - } -} - -impl CompileResult { - pub fn is_ok(&self) -> bool { - self.value.is_some() && self.errors.is_empty() - } - - pub fn is_ok_no_warn(&self) -> bool { - self.is_ok() && self.warnings.is_empty() - } - - pub fn new(value: Option, warnings: Vec, errors: Vec) -> Self { - CompileResult { - value, - warnings, - errors, - } - } - - pub fn with_handler(run: impl FnOnce(&Handler) -> Result) -> CompileResult { - let handler = <_>::default(); - Self::from_handler(run(&handler).ok(), handler) - } - - pub fn from_handler(value: Option, handler: Handler) -> Self { - let (errors, warnings) = handler.consume(); - Self::new(value, warnings, errors) - } - - pub fn ok( - mut self, - warnings: &mut Vec, - errors: &mut Vec, - ) -> Option { - warnings.append(&mut self.warnings); - errors.append(&mut self.errors); - self.value - } - - pub fn map U>(self, f: F) -> CompileResult { - match self.value { - None => err(self.warnings, self.errors), - Some(value) => ok(f(value), self.warnings, self.errors), - } - } - - pub fn flat_map CompileResult>(self, f: F) -> CompileResult { - match self.value { - None => err(self.warnings, self.errors), - Some(value) => { - let res = f(value); - CompileResult { - value: res.value, - warnings: [self.warnings, res.warnings].concat(), - errors: [self.errors, res.errors].concat(), - } - } - } - } - - pub fn unwrap(self, warnings: &mut Vec, errors: &mut Vec) -> T { - let panic_msg = format!("Unwrapped an err {:?}", self.errors); - self.unwrap_or_else(warnings, errors, || panic!("{}", panic_msg)) - } - - pub fn unwrap_or_else T>( - self, - warnings: &mut Vec, - errors: &mut Vec, - or_else: F, - ) -> T { - self.ok(warnings, errors).unwrap_or_else(or_else) - } -} - -impl<'a, T> CompileResult<&'a T> -where - T: Clone, -{ - /// Converts a `CompileResult` around a reference value to an owned value by cloning the type - /// behind the reference. - pub fn cloned(self) -> CompileResult { - let CompileResult { - value, - warnings, - errors, - } = self; - let value = value.cloned(); - CompileResult { - value, - warnings, - errors, - } - } -} diff --git a/sway-core/src/ir_generation/compile.rs b/sway-core/src/ir_generation/compile.rs index 27514ec7459..0e655e43d9b 100644 --- a/sway-core/src/ir_generation/compile.rs +++ b/sway-core/src/ir_generation/compile.rs @@ -14,7 +14,7 @@ use super::{ function::FnCompiler, }; -use sway_error::error::CompileError; +use sway_error::{error::CompileError, handler::Handler}; use sway_ir::{metadata::combine as md_combine, *}; use sway_types::Spanned; @@ -531,10 +531,10 @@ fn compile_abi_method( engines: &Engines, ) -> Result { // Use the error from .to_fn_selector_value() if possible, else make an CompileError::Internal. - let get_selector_result = ast_fn_decl.to_fn_selector_value(engines); - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let selector = match get_selector_result.ok(&mut warnings, &mut errors) { + let handler = Handler::default(); + let get_selector_result = ast_fn_decl.to_fn_selector_value(&handler, engines); + let (errors, _warnings) = handler.consume(); + let selector = match get_selector_result.ok() { Some(selector) => selector, None => { return if !errors.is_empty() { diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index 85fec65b37a..43b096e13fb 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -926,6 +926,7 @@ fn const_eval_intrinsic( #[cfg(test)] mod tests { use super::*; + use sway_error::handler::Handler; use sway_ir::Kind; /// This function validates if an expression can be converted to [Constant]. @@ -943,6 +944,7 @@ mod tests { /// It DOES NOT have access to the std lib, and constants, and other features that demand full compilation. fn assert_is_constant(is_constant: bool, prefix: &str, expr: &str) { let engines = Engines::default(); + let handler = Handler::default(); let mut context = Context::new(engines.se()); let mut md_mgr = MetadataManager::default(); let core_lib = namespace::Module::default(); @@ -950,6 +952,7 @@ mod tests { let mut performance_data = sway_utils::PerformanceData::default(); let r = crate::compile_to_ast( + &handler, &engines, std::sync::Arc::from(format!("library; {prefix} fn f() -> u64 {{ {expr}; 0 }}")), core_lib, @@ -958,11 +961,13 @@ mod tests { &mut performance_data, ); - if !r.errors.is_empty() { - panic!("{:#?}", r.errors); + let (errors, _warnings) = handler.consume(); + + if !errors.is_empty() { + panic!("{:#?}", errors); } - let f = r.value.unwrap(); + let f = r.unwrap(); let f = f.typed.unwrap(); let f = f diff --git a/sway-core/src/language/ty/ast_node.rs b/sway-core/src/language/ty/ast_node.rs index 3d17dd0f441..229d27b183b 100644 --- a/sway-core/src/language/ty/ast_node.rs +++ b/sway-core/src/language/ty/ast_node.rs @@ -3,12 +3,12 @@ use std::{ hash::{Hash, Hasher}, }; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Ident, Span}; use crate::{ decl_engine::*, engine_threading::*, - error::*, language::{parsed::TreeType, ty::*, Visibility}, transform::AttributeKind, type_system::*, @@ -120,9 +120,10 @@ impl UpdateConstantExpression for TyAstNode { impl CollectTypesMetadata for TyAstNode { fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { - self.content.collect_types_metadata(ctx) + ) -> Result, ErrorEmitted> { + self.content.collect_types_metadata(handler, ctx) } } @@ -354,14 +355,15 @@ impl HashWithEngines for TyAstNodeContent { impl CollectTypesMetadata for TyAstNodeContent { fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { + ) -> Result, ErrorEmitted> { use TyAstNodeContent::*; match self { - Declaration(decl) => decl.collect_types_metadata(ctx), - Expression(expr) => expr.collect_types_metadata(ctx), - ImplicitReturnExpression(expr) => expr.collect_types_metadata(ctx), - SideEffect(_) => ok(vec![], vec![], vec![]), + Declaration(decl) => decl.collect_types_metadata(handler, ctx), + Expression(expr) => expr.collect_types_metadata(handler, ctx), + ImplicitReturnExpression(expr) => expr.collect_types_metadata(handler, ctx), + SideEffect(_) => Ok(vec![]), } } } diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index 3e7d6faa7f1..b367ec364ec 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -3,13 +3,15 @@ use std::{ hash::{Hash, Hasher}, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span, Spanned}; use crate::{ decl_engine::*, engine_threading::*, - error::*, language::{ty::*, Visibility}, type_system::*, types::*, @@ -502,47 +504,31 @@ impl CollectTypesMetadata for TyDecl { // this is only run on entry nodes, which must have all well-formed types fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result, ErrorEmitted> { let decl_engine = ctx.engines.de(); let metadata = match self { TyDecl::VariableDecl(decl) => { - let mut body = check!( - decl.body.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors + let mut body = decl.body.collect_types_metadata(handler, ctx)?; + body.append( + &mut decl + .type_ascription + .type_id + .collect_types_metadata(handler, ctx)?, ); - body.append(&mut check!( - decl.type_ascription.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); body } TyDecl::FunctionDecl(FunctionDecl { decl_id, .. }) => { let decl = decl_engine.get_function(decl_id); - check!( - decl.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - ) + decl.collect_types_metadata(handler, ctx)? } TyDecl::ConstantDecl(ConstantDecl { decl_id, .. }) => { let TyConstantDecl { value, .. } = decl_engine.get_constant(decl_id); if let Some(value) = value { - check!( - value.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - ) + value.collect_types_metadata(handler, ctx)? } else { - return ok(vec![], warnings, errors); + return Ok(vec![]); } } TyDecl::ErrorRecovery(_) @@ -556,11 +542,7 @@ impl CollectTypesMetadata for TyDecl { | TyDecl::TypeAliasDecl(_) | TyDecl::GenericTypeForFunctionScope(_) => vec![], }; - if errors.is_empty() { - ok(metadata, warnings, errors) - } else { - err(warnings, errors) - } + Ok(metadata) } } @@ -590,155 +572,141 @@ impl TyDecl { /// Retrieves the declaration as a `DeclRef>`. /// /// Returns an error if `self` is not the [TyDecl][EnumDecl] variant. - pub(crate) fn to_enum_ref(&self, engines: &Engines) -> CompileResult { + pub(crate) fn to_enum_ref( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result { match self { TyDecl::EnumDecl(EnumDecl { name, decl_id, subst_list: _, decl_span, - }) => ok( - DeclRef::new(name.clone(), *decl_id, decl_span.clone()), - vec![], - vec![], - ), + }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), TyDecl::TypeAliasDecl(TypeAliasDecl { decl_id, .. }) => { let TyTypeAliasDecl { ty, span, .. } = engines.de().get_type_alias(decl_id); - engines.te().get(ty.type_id).expect_enum(engines, "", &span) - } - TyDecl::ErrorRecovery(_) => err(vec![], vec![]), - decl => err( - vec![], - vec![CompileError::DeclIsNotAnEnum { - actually: decl.friendly_type_name().to_string(), - span: decl.span(), - }], - ), + engines + .te() + .get(ty.type_id) + .expect_enum(handler, engines, "", &span) + } + TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + decl => Err(handler.emit_err(CompileError::DeclIsNotAnEnum { + actually: decl.friendly_type_name().to_string(), + span: decl.span(), + })), } } /// Retrieves the declaration as a `DeclRef>`. /// /// Returns an error if `self` is not the [TyDecl][StructDecl] variant. - pub(crate) fn to_struct_ref(&self, engines: &Engines) -> CompileResult { + pub(crate) fn to_struct_ref( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result { match self { TyDecl::StructDecl(StructDecl { name, decl_id, subst_list: _, decl_span, - }) => ok( - DeclRef::new(name.clone(), *decl_id, decl_span.clone()), - vec![], - vec![], - ), + }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), TyDecl::TypeAliasDecl(TypeAliasDecl { decl_id, .. }) => { let TyTypeAliasDecl { ty, span, .. } = engines.de().get_type_alias(decl_id); - engines.te().get(ty.type_id).expect_struct(engines, &span) - } - TyDecl::ErrorRecovery(_) => err(vec![], vec![]), - decl => err( - vec![], - vec![CompileError::DeclIsNotAStruct { - actually: decl.friendly_type_name().to_string(), - span: decl.span(), - }], - ), + engines + .te() + .get(ty.type_id) + .expect_struct(handler, engines, &span) + } + TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + decl => Err(handler.emit_err(CompileError::DeclIsNotAStruct { + actually: decl.friendly_type_name().to_string(), + span: decl.span(), + })), } } /// Retrieves the declaration as a `DeclRef>`. /// /// Returns an error if `self` is not the [TyDecl][FunctionDecl] variant. - pub(crate) fn to_fn_ref(&self) -> CompileResult>> { + pub(crate) fn to_fn_ref( + &self, + handler: &Handler, + ) -> Result>, ErrorEmitted> { match self { TyDecl::FunctionDecl(FunctionDecl { name, decl_id, subst_list: _, decl_span, - }) => ok( - DeclRef::new(name.clone(), *decl_id, decl_span.clone()), - vec![], - vec![], - ), - TyDecl::ErrorRecovery(_) => err(vec![], vec![]), - decl => err( - vec![], - vec![CompileError::DeclIsNotAFunction { - actually: decl.friendly_type_name().to_string(), - span: decl.span(), - }], - ), + }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), + TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + decl => Err(handler.emit_err(CompileError::DeclIsNotAFunction { + actually: decl.friendly_type_name().to_string(), + span: decl.span(), + })), } } /// Retrieves the declaration as a variable declaration. /// /// Returns an error if `self` is not a [TyVariableDecl]. - pub(crate) fn expect_variable(&self) -> CompileResult<&TyVariableDecl> { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn expect_variable( + &self, + handler: &Handler, + ) -> Result<&TyVariableDecl, ErrorEmitted> { match self { - TyDecl::VariableDecl(decl) => ok(decl, warnings, errors), - TyDecl::ErrorRecovery(_) => err(vec![], vec![]), - decl => { - errors.push(CompileError::DeclIsNotAVariable { - actually: decl.friendly_type_name().to_string(), - span: decl.span(), - }); - err(warnings, errors) - } + TyDecl::VariableDecl(decl) => Ok(decl), + TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + decl => Err(handler.emit_err(CompileError::DeclIsNotAVariable { + actually: decl.friendly_type_name().to_string(), + span: decl.span(), + })), } } /// Retrieves the declaration as a `DeclRef>`. /// /// Returns an error if `self` is not the [TyDecl][AbiDecl] variant. - pub(crate) fn to_abi_ref(&self) -> CompileResult>> { + pub(crate) fn to_abi_ref( + &self, + handler: &Handler, + ) -> Result>, ErrorEmitted> { match self { TyDecl::AbiDecl(AbiDecl { name, decl_id, decl_span, - }) => ok( - DeclRef::new(name.clone(), *decl_id, decl_span.clone()), - vec![], - vec![], - ), - TyDecl::ErrorRecovery(_) => err(vec![], vec![]), - decl => err( - vec![], - vec![CompileError::DeclIsNotAnAbi { - actually: decl.friendly_type_name().to_string(), - span: decl.span(), - }], - ), + }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), + TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + decl => Err(handler.emit_err(CompileError::DeclIsNotAnAbi { + actually: decl.friendly_type_name().to_string(), + span: decl.span(), + })), } } /// Retrieves the declaration as a `DeclRef>`. /// /// Returns an error if `self` is not the [TyDecl][ConstantDecl] variant. - pub(crate) fn to_const_ref(&self) -> CompileResult>> { + pub(crate) fn to_const_ref( + &self, + handler: &Handler, + ) -> Result>, ErrorEmitted> { match self { TyDecl::ConstantDecl(ConstantDecl { name, decl_id, decl_span, - }) => ok( - DeclRef::new(name.clone(), *decl_id, decl_span.clone()), - vec![], - vec![], - ), - TyDecl::ErrorRecovery(_) => err(vec![], vec![]), - decl => err( - vec![], - vec![CompileError::DeclIsNotAConstant { - actually: decl.friendly_type_name().to_string(), - span: decl.span(), - }], - ), + }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), + TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + decl => Err(handler.emit_err(CompileError::DeclIsNotAConstant { + actually: decl.friendly_type_name().to_string(), + span: decl.span(), + })), } } @@ -802,9 +770,11 @@ impl TyDecl { } } - pub(crate) fn return_type(&self, engines: &Engines) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn return_type( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result { let type_engine = engines.te(); let decl_engine = engines.de(); let type_id = match self { @@ -848,15 +818,14 @@ impl TyDecl { type_id, .. }) => *type_id, decl => { - errors.push(CompileError::NotAType { + return Err(handler.emit_err(CompileError::NotAType { span: decl.span(), name: engines.help_out(decl).to_string(), actually_is: decl.friendly_type_name(), - }); - return err(warnings, errors); + })); } }; - ok(type_id, warnings, errors) + Ok(type_id) } pub(crate) fn visibility(&self, decl_engine: &DeclEngine) -> Visibility { diff --git a/sway-core/src/language/ty/declaration/enum.rs b/sway-core/src/language/ty/declaration/enum.rs index a31788472fa..2b40f9bcdf3 100644 --- a/sway-core/src/language/ty/declaration/enum.rs +++ b/sway-core/src/language/ty/declaration/enum.rs @@ -3,12 +3,14 @@ use std::{ hash::{Hash, Hasher}, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Named, Span, Spanned}; use crate::{ engine_threading::*, - error::*, language::{CallPath, Visibility}, transform, type_system::*, @@ -100,24 +102,20 @@ impl MonomorphizeHelper for TyEnumDecl { impl TyEnumDecl { pub(crate) fn expect_variant_from_name( &self, + handler: &Handler, variant_name: &Ident, - ) -> CompileResult<&TyEnumVariant> { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result<&TyEnumVariant, ErrorEmitted> { match self .variants .iter() .find(|x| x.name.as_str() == variant_name.as_str()) { - Some(variant) => ok(variant, warnings, errors), - None => { - errors.push(CompileError::UnknownEnumVariant { - enum_name: self.call_path.suffix.clone(), - variant_name: variant_name.clone(), - span: variant_name.span(), - }); - err(warnings, errors) - } + Some(variant) => Ok(variant), + None => Err(handler.emit_err(CompileError::UnknownEnumVariant { + enum_name: self.call_path.suffix.clone(), + variant_name: variant_name.clone(), + span: variant_name.span(), + })), } } } diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index f9f5519fa73..9c577a0e756 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -4,11 +4,11 @@ use std::{ }; use sha2::{Digest, Sha256}; +use sway_error::handler::{ErrorEmitted, Handler}; use crate::{ decl_engine::*, engine_threading::*, - error::*, language::{parsed, ty::*, Inline, Purity, Visibility}, transform, type_system::*, @@ -179,42 +179,31 @@ impl UnconstrainedTypeParameters for TyFunctionDecl { impl CollectTypesMetadata for TyFunctionDecl { fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result, ErrorEmitted> { let mut body = vec![]; for content in self.body.contents.iter() { - body.append(&mut check!( - content.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + body.append(&mut content.collect_types_metadata(handler, ctx)?); } - body.append(&mut check!( - self.return_type.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + body.append( + &mut self + .return_type + .type_id + .collect_types_metadata(handler, ctx)?, + ); for type_param in self.type_parameters.iter() { - body.append(&mut check!( - type_param.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + body.append(&mut type_param.type_id.collect_types_metadata(handler, ctx)?); } for param in self.parameters.iter() { - body.append(&mut check!( - param.type_argument.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + body.append( + &mut param + .type_argument + .type_id + .collect_types_metadata(handler, ctx)?, + ); } - ok(body, warnings, errors) + Ok(body) } } @@ -267,42 +256,38 @@ impl TyFunctionDecl { } } - pub fn to_fn_selector_value_untruncated(&self, engines: &Engines) -> CompileResult> { - let mut errors = vec![]; - let mut warnings = vec![]; + pub fn to_fn_selector_value_untruncated( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result, ErrorEmitted> { let mut hasher = Sha256::new(); - let data = check!( - self.to_selector_name(engines), - return err(warnings, errors), - warnings, - errors - ); + let data = self.to_selector_name(handler, engines)?; hasher.update(data); let hash = hasher.finalize(); - ok(hash.to_vec(), warnings, errors) + Ok(hash.to_vec()) } /// Converts a [TyFunctionDecl] into a value that is to be used in contract function /// selectors. /// Hashes the name and parameters using SHA256, and then truncates to four bytes. - pub fn to_fn_selector_value(&self, engines: &Engines) -> CompileResult<[u8; 4]> { - let mut errors = vec![]; - let mut warnings = vec![]; - let hash = check!( - self.to_fn_selector_value_untruncated(engines), - return err(warnings, errors), - warnings, - errors - ); + pub fn to_fn_selector_value( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result<[u8; 4], ErrorEmitted> { + let hash = self.to_fn_selector_value_untruncated(handler, engines)?; // 4 bytes truncation via copying into a 4 byte buffer let mut buf = [0u8; 4]; buf.copy_from_slice(&hash[..4]); - ok(buf, warnings, errors) + Ok(buf) } - pub fn to_selector_name(&self, engines: &Engines) -> CompileResult { - let mut errors = vec![]; - let mut warnings = vec![]; + pub fn to_selector_name( + &self, + handler: &Handler, + engines: &Engines, + ) -> Result { let named_params = self .parameters .iter() @@ -311,16 +296,16 @@ impl TyFunctionDecl { .te() .to_typeinfo(type_argument.type_id, &type_argument.span) .expect("unreachable I think?") - .to_selector_name(engines, &type_argument.span) + .to_selector_name(handler, engines, &type_argument.span) }) - .filter_map(|name| name.ok(&mut warnings, &mut errors)) + .filter_map(|name| name.ok()) .collect::>(); - ok( - format!("{}({})", self.name.as_str(), named_params.join(","),), - warnings, - errors, - ) + Ok(format!( + "{}({})", + self.name.as_str(), + named_params.join(","), + )) } /// Whether or not this function is the default entry point. diff --git a/sway-core/src/language/ty/declaration/storage.rs b/sway-core/src/language/ty/declaration/storage.rs index 5277fb4cac1..4ab4662aeb6 100644 --- a/sway-core/src/language/ty/declaration/storage.rs +++ b/sway-core/src/language/ty/declaration/storage.rs @@ -1,11 +1,13 @@ use std::hash::{Hash, Hasher}; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{state::StateIndex, Ident, Named, Span, Spanned}; use crate::{ - decl_engine::DeclEngine, engine_threading::*, error::*, language::ty::*, transform, - type_system::*, + decl_engine::DeclEngine, engine_threading::*, language::ty::*, transform, type_system::*, }; #[derive(Clone, Debug)] @@ -54,15 +56,13 @@ impl TyStorageDecl { /// been declared as a part of storage, return an error. pub fn apply_storage_load( &self, + handler: &Handler, type_engine: &TypeEngine, decl_engine: &DeclEngine, fields: Vec, storage_fields: &[TyStorageField], storage_keyword_span: Span, - ) -> CompileResult<(TyStorageAccess, TypeId)> { - let mut errors = vec![]; - let warnings = vec![]; - + ) -> Result<(TyStorageAccess, TypeId), ErrorEmitted> { let mut type_checked_buf = vec![]; let mut fields: Vec<_> = fields.into_iter().rev().collect(); @@ -76,11 +76,10 @@ impl TyStorageDecl { (StateIndex::new(ix), type_argument.type_id) } None => { - errors.push(CompileError::StorageFieldDoesNotExist { + return Err(handler.emit_err(CompileError::StorageFieldDoesNotExist { name: first_field.clone(), span: first_field.span(), - }); - return err(warnings, errors); + })); } }; @@ -120,31 +119,26 @@ impl TyStorageDecl { .iter() .map(|x| x.name.as_str()) .collect::>(); - errors.push(CompileError::FieldNotFound { + return Err(handler.emit_err(CompileError::FieldNotFound { field_name: field.clone(), available_fields: available_fields.join(", "), struct_name: type_checked_buf.last().unwrap().name.clone(), span: field.span(), - }); - return err(warnings, errors); + })); } } } let return_type = type_checked_buf[type_checked_buf.len() - 1].type_id; - ok( - ( - TyStorageAccess { - fields: type_checked_buf, - ix, - storage_keyword_span, - }, - return_type, - ), - warnings, - errors, - ) + Ok(( + TyStorageAccess { + fields: type_checked_buf, + ix, + storage_keyword_span, + }, + return_type, + )) } pub(crate) fn fields_as_typed_struct_fields(&self) -> Vec { diff --git a/sway-core/src/language/ty/declaration/struct.rs b/sway-core/src/language/ty/declaration/struct.rs index 07562ca2645..ea089a75e54 100644 --- a/sway-core/src/language/ty/declaration/struct.rs +++ b/sway-core/src/language/ty/declaration/struct.rs @@ -3,12 +3,14 @@ use std::{ hash::{Hash, Hasher}, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Named, Span, Spanned}; use crate::{ engine_threading::*, - error::*, language::{CallPath, Visibility}, transform, type_system::*, @@ -98,17 +100,19 @@ impl MonomorphizeHelper for TyStructDecl { } impl TyStructDecl { - pub(crate) fn expect_field(&self, field_to_access: &Ident) -> CompileResult<&TyStructField> { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn expect_field( + &self, + handler: &Handler, + field_to_access: &Ident, + ) -> Result<&TyStructField, ErrorEmitted> { match self .fields .iter() .find(|TyStructField { name, .. }| name.as_str() == field_to_access.as_str()) { - Some(field) => ok(field, warnings, errors), + Some(field) => Ok(field), None => { - errors.push(CompileError::FieldNotFound { + return Err(handler.emit_err(CompileError::FieldNotFound { available_fields: self .fields .iter() @@ -118,8 +122,7 @@ impl TyStructDecl { field_name: field_to_access.clone(), struct_name: self.call_path.suffix.clone(), span: field_to_access.span(), - }); - err(warnings, errors) + })); } } } diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index 9caf72acc32..fbdcab7a0a4 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -1,11 +1,11 @@ use std::{fmt, hash::Hasher}; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Span, Spanned}; use crate::{ decl_engine::*, engine_threading::*, - error::*, language::{ty::*, Literal}, type_system::*, types::*, @@ -96,18 +96,12 @@ impl DebugWithEngines for TyExpression { impl CollectTypesMetadata for TyExpression { fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { + ) -> Result, ErrorEmitted> { use TyExpressionVariant::*; - let mut warnings = vec![]; - let mut errors = vec![]; let decl_engine = ctx.engines.de(); - let mut res = check!( - self.return_type.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - ); + let mut res = self.return_type.collect_types_metadata(handler, ctx)?; match &self.expression { FunctionApplication { arguments, @@ -116,12 +110,7 @@ impl CollectTypesMetadata for TyExpression { .. } => { for arg in arguments.iter() { - res.append(&mut check!( - arg.1.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut arg.1.collect_types_metadata(handler, ctx)?); } let function_decl = decl_engine.get_function(fn_ref); @@ -131,34 +120,19 @@ impl CollectTypesMetadata for TyExpression { } for content in function_decl.body.contents.iter() { - res.append(&mut check!( - content.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut content.collect_types_metadata(handler, ctx)?); } ctx.call_site_pop(); } Tuple { fields } => { for field in fields.iter() { - res.append(&mut check!( - field.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut field.collect_types_metadata(handler, ctx)?); } } AsmExpression { registers, .. } => { for register in registers.iter() { if let Some(init) = register.initializer.as_ref() { - res.append(&mut check!( - init.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut init.collect_types_metadata(handler, ctx)?); } } } @@ -179,95 +153,42 @@ impl CollectTypesMetadata for TyExpression { } } for field in fields.iter() { - res.append(&mut check!( - field.value.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut field.value.collect_types_metadata(handler, ctx)?); } } LazyOperator { lhs, rhs, .. } => { - res.append(&mut check!( - lhs.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - res.append(&mut check!( - rhs.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut lhs.collect_types_metadata(handler, ctx)?); + res.append(&mut rhs.collect_types_metadata(handler, ctx)?); } Array { elem_type: _, contents, } => { for content in contents.iter() { - res.append(&mut check!( - content.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut content.collect_types_metadata(handler, ctx)?); } } ArrayIndex { prefix, index } => { - res.append(&mut check!( - (**prefix).collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - res.append(&mut check!( - (**index).collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut (**prefix).collect_types_metadata(handler, ctx)?); + res.append(&mut (**index).collect_types_metadata(handler, ctx)?); } CodeBlock(block) => { for content in block.contents.iter() { - res.append(&mut check!( - content.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut content.collect_types_metadata(handler, ctx)?); } } - MatchExp { desugared, .. } => res.append(&mut check!( - desugared.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )), + MatchExp { desugared, .. } => { + res.append(&mut desugared.collect_types_metadata(handler, ctx)?) + } IfExp { condition, then, r#else, } => { - res.append(&mut check!( - condition.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - res.append(&mut check!( - then.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut condition.collect_types_metadata(handler, ctx)?); + res.append(&mut then.collect_types_metadata(handler, ctx)?); if let Some(r#else) = r#else { - res.append(&mut check!( - r#else.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut r#else.collect_types_metadata(handler, ctx)?); } } StructFieldAccess { @@ -275,36 +196,16 @@ impl CollectTypesMetadata for TyExpression { resolved_type_of_parent, .. } => { - res.append(&mut check!( - prefix.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - res.append(&mut check!( - resolved_type_of_parent.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut prefix.collect_types_metadata(handler, ctx)?); + res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?); } TupleElemAccess { prefix, resolved_type_of_parent, .. } => { - res.append(&mut check!( - prefix.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - res.append(&mut check!( - resolved_type_of_parent.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut prefix.collect_types_metadata(handler, ctx)?); + res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?); } EnumInstantiation { enum_ref, @@ -317,94 +218,49 @@ impl CollectTypesMetadata for TyExpression { ctx.call_site_insert(type_param.type_id, call_path_binding.inner.suffix.span()) } if let Some(contents) = contents { - res.append(&mut check!( - contents.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut contents.collect_types_metadata(handler, ctx)?); } for variant in enum_decl.variants.iter() { - res.append(&mut check!( - variant.type_argument.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append( + &mut variant + .type_argument + .type_id + .collect_types_metadata(handler, ctx)?, + ); } for type_param in enum_decl.type_parameters.iter() { - res.append(&mut check!( - type_param.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut type_param.type_id.collect_types_metadata(handler, ctx)?); } } AbiCast { address, .. } => { - res.append(&mut check!( - address.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut address.collect_types_metadata(handler, ctx)?); } IntrinsicFunction(kind) => { - res.append(&mut check!( - kind.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut kind.collect_types_metadata(handler, ctx)?); } EnumTag { exp } => { - res.append(&mut check!( - exp.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut exp.collect_types_metadata(handler, ctx)?); } UnsafeDowncast { exp, variant, call_path_decl: _, } => { - res.append(&mut check!( - exp.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - res.append(&mut check!( - variant.type_argument.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut exp.collect_types_metadata(handler, ctx)?); + res.append( + &mut variant + .type_argument + .type_id + .collect_types_metadata(handler, ctx)?, + ); } WhileLoop { condition, body } => { - res.append(&mut check!( - condition.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut condition.collect_types_metadata(handler, ctx)?); for content in body.contents.iter() { - res.append(&mut check!( - content.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut content.collect_types_metadata(handler, ctx)?); } } - Return(exp) => res.append(&mut check!( - exp.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )), + Return(exp) => res.append(&mut exp.collect_types_metadata(handler, ctx)?), // storage access can never be generic // variable expressions don't ever have return types themselves, they're stored in // `TyExpression::return_type`. Variable expressions are just names of variables. @@ -417,15 +273,10 @@ impl CollectTypesMetadata for TyExpression { | Continue | FunctionParameter => {} Reassignment(reassignment) => { - res.append(&mut check!( - reassignment.rhs.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + res.append(&mut reassignment.rhs.collect_types_metadata(handler, ctx)?); } } - ok(res, warnings, errors) + Ok(res) } } diff --git a/sway-core/src/language/ty/expression/intrinsic_function.rs b/sway-core/src/language/ty/expression/intrinsic_function.rs index 649b6d43141..4b25f4205fe 100644 --- a/sway-core/src/language/ty/expression/intrinsic_function.rs +++ b/sway-core/src/language/ty/expression/intrinsic_function.rs @@ -4,11 +4,11 @@ use std::{ }; use crate::{ - decl_engine::DeclEngine, engine_threading::*, error::*, language::ty::*, type_system::*, - types::*, + decl_engine::DeclEngine, engine_threading::*, language::ty::*, type_system::*, types::*, }; use itertools::Itertools; use sway_ast::Intrinsic; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; #[derive(Debug, Clone)] @@ -96,26 +96,15 @@ impl DeterministicallyAborts for TyIntrinsicFunctionKind { impl CollectTypesMetadata for TyIntrinsicFunctionKind { fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result, ErrorEmitted> { let mut types_metadata = vec![]; for type_arg in self.type_arguments.iter() { - types_metadata.append(&mut check!( - type_arg.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + types_metadata.append(&mut type_arg.type_id.collect_types_metadata(handler, ctx)?); } for arg in self.arguments.iter() { - types_metadata.append(&mut check!( - arg.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + types_metadata.append(&mut arg.collect_types_metadata(handler, ctx)?); } match self.kind { @@ -136,6 +125,6 @@ impl CollectTypesMetadata for TyIntrinsicFunctionKind { _ => {} } - ok(types_metadata, warnings, errors) + Ok(types_metadata) } } diff --git a/sway-core/src/language/ty/program.rs b/sway-core/src/language/ty/program.rs index dc59ee94b14..36732c6b84e 100644 --- a/sway-core/src/language/ty/program.rs +++ b/sway-core/src/language/ty/program.rs @@ -1,6 +1,5 @@ use crate::{ decl_engine::*, - error::*, fuel_prelude::fuel_tx::StorageSlot, language::{parsed, ty::*, Purity}, type_system::*, @@ -8,7 +7,10 @@ use crate::{ Engines, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::*; #[derive(Debug, Clone)] @@ -25,14 +27,13 @@ pub struct TyProgram { impl TyProgram { /// Validate the root module given the expected program kind. pub fn validate_root( + handler: &Handler, engines: &Engines, root: &TyModule, kind: parsed::TreeType, package_name: &str, - ) -> CompileResult<(TyProgramKind, Vec, Vec)> { + ) -> Result<(TyProgramKind, Vec, Vec), ErrorEmitted> { // Extract program-kind-specific properties from the root nodes. - let mut errors = vec![]; - let mut warnings = vec![]; let ty_engine = engines.te(); let decl_engine = engines.de(); @@ -40,17 +41,16 @@ impl TyProgram { // Validate all submodules let mut configurables = Vec::::new(); for (_, submodule) in &root.submodules { - check!( - Self::validate_root( - engines, - &submodule.module, - parsed::TreeType::Library, - package_name, - ), - continue, - warnings, - errors - ); + match Self::validate_root( + handler, + engines, + &submodule.module, + parsed::TreeType::Library, + package_name, + ) { + Ok(_) => {} + Err(_) => continue, + } } let mut mains = Vec::new(); @@ -72,7 +72,7 @@ impl TyProgram { } if !fn_declarations.insert(func.name.clone()) { - errors.push(CompileError::MultipleDefinitionsOfFunction { + handler.emit_err(CompileError::MultipleDefinitionsOfFunction { name: func.name.clone(), span: func.name.span(), }); @@ -141,11 +141,9 @@ impl TyProgram { if kind != parsed::TreeType::Contract { // impure functions are disallowed in non-contracts if !matches!(kind, parsed::TreeType::Library { .. }) { - errors.extend(disallow_impure_functions( - decl_engine, - &declarations, - &mains, - )); + for err in disallow_impure_functions(decl_engine, &declarations, &mains) { + handler.emit_err(err); + } } // `storage` declarations are not allowed in non-contracts @@ -154,7 +152,7 @@ impl TyProgram { .find(|decl| matches!(decl, TyDecl::StorageDecl { .. })); if let Some(TyDecl::StorageDecl(StorageDecl { decl_span, .. })) = storage_decl { - errors.push(CompileError::StorageDeclarationInNonContract { + handler.emit_err(CompileError::StorageDeclarationInNonContract { program_kind: format!("{kind}"), span: decl_span.clone(), }); @@ -183,7 +181,7 @@ impl TyProgram { ) .is_empty() { - errors.push(CompileError::TypeNotAllowedInContractStorage { + handler.emit_err(CompileError::TypeNotAllowedInContractStorage { ty: engines .help_out(&ty_engine.get(field.type_argument.type_id)) .to_string(), @@ -198,7 +196,7 @@ impl TyProgram { } parsed::TreeType::Library => { if !configurables.is_empty() { - errors.push(CompileError::ConfigurableInLibrary { + handler.emit_err(CompileError::ConfigurableInLibrary { span: configurables[0].call_path.suffix.span(), }); } @@ -209,11 +207,12 @@ impl TyProgram { parsed::TreeType::Predicate => { // A predicate must have a main function and that function must return a boolean. if mains.is_empty() { - errors.push(CompileError::NoPredicateMainFunction(root.span.clone())); - return err(vec![], errors); + return Err( + handler.emit_err(CompileError::NoPredicateMainFunction(root.span.clone())) + ); } if mains.len() > 1 { - errors.push(CompileError::MultipleDefinitionsOfFunction { + handler.emit_err(CompileError::MultipleDefinitionsOfFunction { name: mains.last().unwrap().name.clone(), span: mains.last().unwrap().name.span(), }); @@ -221,9 +220,11 @@ impl TyProgram { let main_func = mains.remove(0); match ty_engine.get(main_func.return_type.type_id) { TypeInfo::Boolean => (), - _ => errors.push(CompileError::PredicateMainDoesNotReturnBool( - main_func.span.clone(), - )), + _ => { + handler.emit_err(CompileError::PredicateMainDoesNotReturnBool( + main_func.span.clone(), + )); + } } TyProgramKind::Predicate { main_function: main_func, @@ -232,11 +233,12 @@ impl TyProgram { parsed::TreeType::Script => { // A script must have exactly one main function. if mains.is_empty() { - errors.push(CompileError::NoScriptMainFunction(root.span.clone())); - return err(vec![], errors); + return Err( + handler.emit_err(CompileError::NoScriptMainFunction(root.span.clone())) + ); } if mains.len() > 1 { - errors.push(CompileError::MultipleDefinitionsOfFunction { + handler.emit_err(CompileError::MultipleDefinitionsOfFunction { name: mains.last().unwrap().name.clone(), span: mains.last().unwrap().name.span(), }); @@ -252,7 +254,7 @@ impl TyProgram { }) .is_empty() { - errors.push(CompileError::NestedSliceReturnNotAllowedInMain { + handler.emit_err(CompileError::NestedSliceReturnNotAllowedInMain { span: main_func.return_type.span.clone(), }); } @@ -267,20 +269,16 @@ impl TyProgram { | TyProgramKind::Predicate { main_function, .. } => { for param in &main_function.parameters { if param.is_reference && param.is_mutable { - errors.push(CompileError::RefMutableNotAllowedInMain { + handler.emit_err(CompileError::RefMutableNotAllowedInMain { param_name: param.name.clone(), span: param.name.span(), - }) + }); } } } _ => (), } - ok( - (typed_program_kind, declarations, configurables), - warnings, - errors, - ) + Ok((typed_program_kind, declarations, configurables)) } /// All test function declarations within the program. @@ -299,10 +297,9 @@ impl CollectTypesMetadata for TyProgram { /// Collect various type information such as unresolved types and types of logged data fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result, ErrorEmitted> { let decl_engine = ctx.engines.de(); let mut metadata = vec![]; @@ -312,23 +309,13 @@ impl CollectTypesMetadata for TyProgram { // `main()` as the only entry point TyProgramKind::Script { main_function, .. } | TyProgramKind::Predicate { main_function, .. } => { - metadata.append(&mut check!( - main_function.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + metadata.append(&mut main_function.collect_types_metadata(handler, ctx)?); } // For contracts, collect metadata for all the types starting with each ABI method as // an entry point. TyProgramKind::Contract { abi_entries, .. } => { for entry in abi_entries.iter() { - metadata.append(&mut check!( - entry.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + metadata.append(&mut entry.collect_types_metadata(handler, ctx)?); } } // For libraries, collect metadata for all the types starting with each `pub` node as @@ -343,12 +330,7 @@ impl CollectTypesMetadata for TyProgram { for node in module.all_nodes.iter() { let is_generic_function = node.is_generic_function(decl_engine); if node.is_public(decl_engine) { - let node_metadata = check!( - node.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - ); + let node_metadata = node.collect_types_metadata(handler, ctx)?; metadata.append( &mut node_metadata .iter() @@ -376,21 +358,12 @@ impl CollectTypesMetadata for TyProgram { ) { for node in module.all_nodes.iter() { if node.is_test_function(decl_engine) { - metadata.append(&mut check!( - node.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); + metadata.append(&mut node.collect_types_metadata(handler, ctx)?); } } } - if errors.is_empty() { - ok(metadata, warnings, errors) - } else { - err(warnings, errors) - } + Ok(metadata) } } diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index 638d5ac9789..b12812e5c54 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -22,7 +22,7 @@ pub mod transform; pub mod type_system; use crate::ir_generation::check_function_purity; -use crate::{error::*, source_map::SourceMap}; +use crate::source_map::SourceMap; pub use asm_generation::from_ir::compile_ir_to_asm; use asm_generation::FinalizedAsm; pub use asm_generation::{CompiledBytecode, FinalizedEntry}; @@ -48,7 +48,6 @@ use types::*; pub use semantic_analysis::namespace::{self, Namespace}; pub mod types; -pub use error::CompileResult; use sway_error::error::CompileError; use sway_error::warning::CompileWarning; use sway_types::{ident::Ident, span, Spanned}; @@ -79,15 +78,16 @@ pub use engine_threading::Engines; /// Panics if the parser panics. pub fn parse( input: Arc, + handler: &Handler, engines: &Engines, config: Option<&BuildConfig>, -) -> CompileResult<(lexed::LexedProgram, parsed::ParseProgram)> { - CompileResult::with_handler(|h| match config { - None => parse_in_memory(h, engines, input), +) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> { + match config { + None => parse_in_memory(handler, engines, input), // When a `BuildConfig` is given, // the module source may declare `dep`s that must be parsed from other files. Some(config) => parse_module_tree( - h, + handler, engines, input, config.canonical_root_module(), @@ -102,16 +102,17 @@ pub fn parse( let parsed = parsed::ParseProgram { kind, root: parsed }; (lexed, parsed) }), - }) + } } /// Parses the tree kind in the input provided. /// /// This will lex the entire input, but parses only the module kind. -pub fn parse_tree_type(input: Arc) -> CompileResult { - CompileResult::with_handler(|h| { - sway_parse::parse_module_kind(h, input, None).map(|kind| convert_module_kind(&kind)) - }) +pub fn parse_tree_type( + handler: &Handler, + input: Arc, +) -> Result { + sway_parse::parse_module_kind(handler, input, None).map(|kind| convert_module_kind(&kind)) } /// Convert attributes from `Annotated` to an [AttributesMap]. @@ -342,35 +343,36 @@ fn module_path( pub struct CompiledAsm(pub FinalizedAsm); pub fn parsed_to_ast( + handler: &Handler, engines: &Engines, parse_program: &parsed::ParseProgram, initial_namespace: namespace::Module, build_config: Option<&BuildConfig>, package_name: &str, -) -> CompileResult { +) -> Result { // Type check the program. - let CompileResult { - value: typed_program_opt, - mut warnings, - mut errors, - } = ty::TyProgram::type_check(engines, parse_program, initial_namespace, package_name); + let typed_program_opt = ty::TyProgram::type_check( + handler, + engines, + parse_program, + initial_namespace, + package_name, + ); let mut typed_program = match typed_program_opt { - Some(typed_program) => typed_program, - None => return err(warnings, errors), + Ok(typed_program) => typed_program, + Err(e) => return Err(e), }; // Collect information about the types used in this program - let CompileResult { - value: types_metadata_result, - warnings: new_warnings, - errors: new_errors, - } = typed_program.collect_types_metadata(&mut CollectTypesMetadataContext::new(engines)); - warnings.extend(new_warnings); - errors.extend(new_errors); + let types_metadata_result = typed_program + .collect_types_metadata(handler, &mut CollectTypesMetadataContext::new(engines)); let types_metadata = match types_metadata_result { - Some(types_metadata) => types_metadata, - None => return deduped_err(warnings, errors), + Ok(types_metadata) => types_metadata, + Err(e) => { + handler.dedup(); + return Err(e); + } }; typed_program @@ -395,10 +397,13 @@ pub fn parsed_to_ast( None => (None, None), }; // Perform control flow analysis and extend with any errors. - let cfa_res = - perform_control_flow_analysis(engines, &typed_program, print_graph, print_graph_url_format); - errors.extend(cfa_res.errors); - warnings.extend(cfa_res.warnings); + let _ = perform_control_flow_analysis( + handler, + engines, + &typed_program, + print_graph, + print_graph_url_format, + ); // Evaluate const declarations, to allow storage slots initializion with consts. let mut ctx = Context::new(engines.se()); @@ -411,30 +416,34 @@ pub fn parsed_to_ast( module, &typed_program.root.namespace, ) { - errors.push(e); + handler.emit_err(e); } // CEI pattern analysis let cei_analysis_warnings = semantic_analysis::cei_pattern_analysis::analyze_program(engines, &typed_program); - warnings.extend(cei_analysis_warnings); + for warn in cei_analysis_warnings { + handler.emit_warn(warn); + } // Check that all storage initializers can be evaluated at compile time. let typed_wiss_res = typed_program.get_typed_program_with_initialized_storage_slots( + handler, engines, &mut ctx, &mut md_mgr, module, ); - warnings.extend(typed_wiss_res.warnings); - errors.extend(typed_wiss_res.errors); - let typed_program_with_storage_slots = match typed_wiss_res.value { - Some(typed_program_with_storage_slots) => typed_program_with_storage_slots, - None => return deduped_err(warnings, errors), + let typed_program_with_storage_slots = match typed_wiss_res { + Ok(typed_program_with_storage_slots) => typed_program_with_storage_slots, + Err(e) => { + handler.dedup(); + return Err(e); + } }; // All unresolved types lead to compile errors. - errors.extend(types_metadata.iter().filter_map(|m| match m { + for err in types_metadata.iter().filter_map(|m| match m { TypeMetadata::UnresolvedType(name, call_site_span_opt) => { Some(CompileError::UnableToInferGeneric { ty: name.as_str().to_string(), @@ -442,41 +451,41 @@ pub fn parsed_to_ast( }) } _ => None, - })); + }) { + handler.emit_err(err); + } // Check if a non-test function calls `#[test]` function. - ok( - typed_program_with_storage_slots, - dedup_unsorted(warnings), - dedup_unsorted(errors), - ) + handler.dedup(); + Ok(typed_program_with_storage_slots) } pub fn compile_to_ast( + handler: &Handler, engines: &Engines, input: Arc, initial_namespace: namespace::Module, build_config: Option<&BuildConfig>, package_name: &str, metrics: &mut PerformanceData, -) -> CompileResult { +) -> Result { // Parse the program to a concrete syntax tree (CST). - let CompileResult { - value: parse_program_opt, - mut warnings, - mut errors, - } = time_expr!( + + let parse_program_opt = time_expr!( "parse the program to a concrete syntax tree (CST)", "parse_cst", - parse(input, engines, build_config), + parse(input, handler, engines, build_config), build_config, metrics ); let (lexed_program, mut parsed_program) = match parse_program_opt { - Some(modules) => modules, - None => return deduped_err(warnings, errors), + Ok(modules) => modules, + Err(e) => { + handler.dedup(); + return Err(e); + } }; // If tests are not enabled, exclude them from `parsed_program`. @@ -492,6 +501,7 @@ pub fn compile_to_ast( "parse the concrete syntax tree (CST) to a typed AST", "parse_ast", parsed_to_ast( + handler, engines, &parsed_program, initial_namespace, @@ -502,73 +512,62 @@ pub fn compile_to_ast( metrics ); - errors.extend(typed_res.errors); - warnings.extend(typed_res.warnings); - - ok( - Programs::new(lexed_program, parsed_program, typed_res.value), - dedup_unsorted(warnings), - dedup_unsorted(errors), - ) + handler.dedup(); + Ok(Programs::new(lexed_program, parsed_program, typed_res.ok())) } /// Given input Sway source code, try compiling to a `CompiledAsm`, /// containing the asm in opcode form (not raw bytes/bytecode). pub fn compile_to_asm( + handler: &Handler, engines: &Engines, input: Arc, initial_namespace: namespace::Module, build_config: BuildConfig, package_name: &str, metrics: &mut PerformanceData, -) -> CompileResult { +) -> Result { let ast_res = compile_to_ast( + handler, engines, input, initial_namespace, Some(&build_config), package_name, metrics, - ); - ast_to_asm(engines, &ast_res, &build_config) + )?; + ast_to_asm(handler, engines, &ast_res, &build_config) } /// Given an AST compilation result, try compiling to a `CompiledAsm`, /// containing the asm in opcode form (not raw bytes/bytecode). pub fn ast_to_asm( + handler: &Handler, engines: &Engines, - ast_res: &CompileResult, + programs: &Programs, build_config: &BuildConfig, -) -> CompileResult { - let programs = match ast_res.value.as_ref() { - Some(programs) => programs, - None => return err(ast_res.warnings.clone(), ast_res.errors.clone()), - }; - +) -> Result { let typed_program = match &programs.typed { Some(typed_program) => typed_program, - None => return err(ast_res.warnings.clone(), ast_res.errors.clone()), + None => return Err(ErrorEmitted), }; - let mut errors = ast_res.errors.clone(); - let mut warnings = ast_res.warnings.clone(); - let asm = check!( - compile_ast_to_ir_to_asm(engines, typed_program, build_config), - return deduped_err(warnings, errors), - warnings, - errors - ); - ok(CompiledAsm(asm), warnings, errors) + let asm = match compile_ast_to_ir_to_asm(handler, engines, typed_program, build_config) { + Ok(res) => res, + Err(_) => { + handler.dedup(); + return Err(ErrorEmitted); + } + }; + Ok(CompiledAsm(asm)) } pub(crate) fn compile_ast_to_ir_to_asm( + handler: &Handler, engines: &Engines, program: &ty::TyProgram, build_config: &BuildConfig, -) -> CompileResult { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - +) -> Result { // the IR pipeline relies on type information being fully resolved. // If type information is found to still be generic or unresolved inside of // IR, this is considered an internal compiler error. To resolve this situation, @@ -583,7 +582,7 @@ pub(crate) fn compile_ast_to_ir_to_asm( let mut ir = match ir_generation::compile_program(program, build_config.include_tests, engines) { Ok(ir) => ir, - Err(e) => return err(warnings, vec![e]), + Err(e) => return Err(handler.emit_err(e)), }; // Find all the entry points for purity checking and DCE. @@ -595,15 +594,11 @@ pub(crate) fn compile_ast_to_ir_to_asm( // Do a purity check on the _unoptimised_ IR. { - let handler = Handler::default(); let mut env = ir_generation::PurityEnv::default(); let mut md_mgr = metadata::MetadataManager::default(); for entry_point in &entry_point_functions { - check_function_purity(&handler, &mut env, &ir, &mut md_mgr, entry_point); + check_function_purity(handler, &mut env, &ir, &mut md_mgr, entry_point); } - let (e, w) = handler.consume(); - warnings.extend(w); - errors.extend(e); } // Initialize the pass manager and register known passes. @@ -638,30 +633,25 @@ pub(crate) fn compile_ast_to_ir_to_asm( } // Run the passes. - let res = CompileResult::with_handler(|handler| { - if let Err(ir_error) = pass_mgr.run(&mut ir, &pass_group) { - Err(handler.emit_err(CompileError::InternalOwned( - ir_error.to_string(), - span::Span::dummy(), - ))) - } else { - Ok(()) - } - }); - check!(res, return err(warnings, errors), warnings, errors); + let res = if let Err(ir_error) = pass_mgr.run(&mut ir, &pass_group) { + Err(handler.emit_err(CompileError::InternalOwned( + ir_error.to_string(), + span::Span::dummy(), + ))) + } else { + Ok(()) + }; + res?; - let final_asm = check!( - compile_ir_to_asm(&ir, Some(build_config)), - return err(warnings, errors), - warnings, - errors - ); + let final_asm = compile_ir_to_asm(handler, &ir, Some(build_config))?; - ok(final_asm, warnings, errors) + Ok(final_asm) } /// Given input Sway source code, compile to [CompiledBytecode], containing the asm in bytecode form. +#[allow(clippy::too_many_arguments)] pub fn compile_to_bytecode( + handler: &Handler, engines: &Engines, input: Arc, initial_namespace: namespace::Module, @@ -669,61 +659,54 @@ pub fn compile_to_bytecode( source_map: &mut SourceMap, package_name: &str, metrics: &mut PerformanceData, -) -> CompileResult { +) -> Result { let asm_res = compile_to_asm( + handler, engines, input, initial_namespace, build_config, package_name, metrics, - ); - asm_to_bytecode(asm_res, source_map, engines.se()) + )?; + asm_to_bytecode(handler, asm_res, source_map, engines.se()) } /// Given the assembly (opcodes), compile to [CompiledBytecode], containing the asm in bytecode form. pub fn asm_to_bytecode( - CompileResult { - value, - mut warnings, - mut errors, - }: CompileResult, + handler: &Handler, + mut asm: CompiledAsm, source_map: &mut SourceMap, source_engine: &SourceEngine, -) -> CompileResult { - match value { - Some(CompiledAsm(mut asm)) => { - let compiled_bytecode = check!( - asm.to_bytecode_mut(source_map, source_engine), - return err(warnings, errors), - warnings, - errors, - ); - ok(compiled_bytecode, warnings, errors) - } - None => err(warnings, errors), - } +) -> Result { + let compiled_bytecode = asm.0.to_bytecode_mut(handler, source_map, source_engine)?; + Ok(compiled_bytecode) } /// Given a [ty::TyProgram], which is type-checked Sway source, construct a graph to analyze /// control flow and determine if it is valid. fn perform_control_flow_analysis( + handler: &Handler, engines: &Engines, program: &ty::TyProgram, print_graph: Option, print_graph_url_format: Option, -) -> CompileResult<()> { - let dca_res = dead_code_analysis(engines, program); +) -> Result<(), ErrorEmitted> { + let dca_res = dead_code_analysis(handler, engines, program); let rpa_errors = return_path_analysis(engines, program); let rpa_res = if rpa_errors.is_empty() { - ok((), vec![], vec![]) + Ok(()) } else { - err(vec![], rpa_errors) + for err in rpa_errors { + handler.emit_err(err); + } + Err(ErrorEmitted) }; - if let Some(graph) = dca_res.clone().value { + if let Ok(graph) = dca_res.clone() { graph.visualize(engines, print_graph, print_graph_url_format); } - dca_res.flat_map(|_| rpa_res) + dca_res?; + rpa_res } /// Constructs a dead code graph from all modules within the graph and then attempts to find dead @@ -731,47 +714,52 @@ fn perform_control_flow_analysis( /// /// Returns the graph that was used for analysis. fn dead_code_analysis<'a>( + handler: &Handler, engines: &'a Engines, program: &ty::TyProgram, -) -> CompileResult> { +) -> Result, ErrorEmitted> { let decl_engine = engines.de(); let mut dead_code_graph = Default::default(); let tree_type = program.kind.tree_type(); - module_dead_code_analysis(engines, &program.root, &tree_type, &mut dead_code_graph).flat_map( - |_| { - let warnings = dead_code_graph.find_dead_code(decl_engine); - ok(dead_code_graph, warnings, vec![]) - }, - ) + module_dead_code_analysis( + handler, + engines, + &program.root, + &tree_type, + &mut dead_code_graph, + )?; + let warnings = dead_code_graph.find_dead_code(decl_engine); + for warn in warnings { + handler.emit_warn(warn) + } + Ok(dead_code_graph) } /// Recursively collect modules into the given `ControlFlowGraph` ready for dead code analysis. fn module_dead_code_analysis<'eng: 'cfg, 'cfg>( + handler: &Handler, engines: &'eng Engines, module: &ty::TyModule, tree_type: &parsed::TreeType, graph: &mut ControlFlowGraph<'cfg>, -) -> CompileResult<()> { - let init_res = ok((), vec![], vec![]); - let submodules_res = module +) -> Result<(), ErrorEmitted> { + module .submodules .iter() - .fold(init_res, |res, (_, submodule)| { + .fold(Ok(()), |res, (_, submodule)| { let tree_type = parsed::TreeType::Library; - res.flat_map(|_| { - module_dead_code_analysis(engines, &submodule.module, &tree_type, graph) - }) - }); - let res = submodules_res.flat_map(|()| { + res?; + module_dead_code_analysis(handler, engines, &submodule.module, &tree_type, graph) + })?; + let res = { ControlFlowGraph::append_module_to_dead_code_graph( engines, &module.all_nodes, tree_type, graph, ) - .map(|_| ok((), vec![], vec![])) - .unwrap_or_else(|error| err(vec![], vec![error])) - }); + .map_err(|err| handler.emit_err(err)) + }; graph.connect_pending_entry_edges(); res } @@ -799,6 +787,7 @@ fn module_return_path_analysis( #[test] fn test_basic_prog() { + let handler = Handler::default(); let engines = Engines::default(); let prog = parse( r#" @@ -881,15 +870,15 @@ fn test_basic_prog() { } "# .into(), + &handler, &engines, None, ); - let mut warnings: Vec = Vec::new(); - let mut errors: Vec = Vec::new(); - prog.unwrap(&mut warnings, &mut errors); + prog.unwrap(); } #[test] fn test_parenthesized() { + let handler = Handler::default(); let engines = Engines::default(); let prog = parse( r#" @@ -900,17 +889,17 @@ fn test_parenthesized() { } "# .into(), + &handler, &engines, None, ); - let mut warnings: Vec = Vec::new(); - let mut errors: Vec = Vec::new(); - prog.unwrap(&mut warnings, &mut errors); + prog.unwrap(); } #[test] fn test_unary_ordering() { use crate::language::{self, parsed}; + let handler = Handler::default(); let engines = Engines::default(); let prog = parse( r#" @@ -921,12 +910,11 @@ fn test_unary_ordering() { !a && b; }"# .into(), + &handler, &engines, None, ); - let mut warnings: Vec = Vec::new(); - let mut errors: Vec = Vec::new(); - let (.., prog) = prog.unwrap(&mut warnings, &mut errors); + let (.., prog) = prog.unwrap(); // this should parse as `(!a) && b`, not `!(a && b)`. So, the top level // expression should be `&&` if let parsed::AstNode { @@ -957,48 +945,3 @@ fn test_unary_ordering() { panic!("Was not ast node") }; } - -/// Return an irrecoverable compile result deduping any errors and warnings. -fn deduped_err(warnings: Vec, errors: Vec) -> CompileResult { - err(dedup_unsorted(warnings), dedup_unsorted(errors)) -} - -/// We want compile errors and warnings to retain their ordering, since typically -/// they are grouped by relevance. However, we want to deduplicate them. -/// Stdlib dedup in Rust assumes sorted data for efficiency, but we don't want that. -/// A hash set would also mess up the order, so this is just a brute force way of doing it -/// with a vector. -fn dedup_unsorted(mut data: Vec) -> Vec { - // TODO(Centril): Consider using `IndexSet` instead for readability. - use smallvec::SmallVec; - use std::collections::hash_map::{DefaultHasher, Entry}; - use std::hash::Hasher; - - let mut write_index = 0; - let mut indexes: HashMap> = HashMap::with_capacity(data.len()); - for read_index in 0..data.len() { - let hash = { - let mut hasher = DefaultHasher::new(); - data[read_index].hash(&mut hasher); - hasher.finish() - }; - let index_vec = match indexes.entry(hash) { - Entry::Occupied(oe) => { - if oe - .get() - .iter() - .any(|index| data[*index] == data[read_index]) - { - continue; - } - oe.into_mut() - } - Entry::Vacant(ve) => ve.insert(SmallVec::new()), - }; - data.swap(write_index, read_index); - index_vec.push(write_index); - write_index += 1; - } - data.truncate(write_index); - data -} diff --git a/sway-core/src/monomorphize/mod.rs b/sway-core/src/monomorphize/mod.rs index b4ead763fc2..86d47f78a25 100644 --- a/sway-core/src/monomorphize/mod.rs +++ b/sway-core/src/monomorphize/mod.rs @@ -7,23 +7,26 @@ mod instructions; mod priv_prelude; mod solve; -use crate::{engine_threading::*, language::ty, CompileResult}; +use crate::{engine_threading::*, language::ty}; use priv_prelude::*; +use sway_error::handler::{ErrorEmitted, Handler}; -pub(super) fn monomorphize(engines: &Engines, module: &mut ty::TyModule) -> CompileResult<()> { - CompileResult::with_handler(|h| { - // Gather the constraints from the typed AST. - let constraints = gather_constraints(engines, h, module)?; +pub(super) fn monomorphize( + handler: &Handler, + engines: &Engines, + module: &mut ty::TyModule, +) -> Result<(), ErrorEmitted> { + // Gather the constraints from the typed AST. + let constraints = gather_constraints(engines, handler, module)?; - // Solve the constraints and get back instructions from the solver. - let mut solver = Solver::new(engines); - solver.solve(h, constraints)?; - let instructions = solver.into_instructions(); + // Solve the constraints and get back instructions from the solver. + let mut solver = Solver::new(engines); + solver.solve(handler, constraints)?; + let instructions = solver.into_instructions(); - // Use the new instructions to monomorphize the AST. - apply_instructions(engines, h, instructions, module)?; + // Use the new instructions to monomorphize the AST. + apply_instructions(engines, handler, instructions, module)?; - Ok(()) - }) + Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index b1c17dbf63e..1f7c071b577 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -6,12 +6,10 @@ use crate::{ impl ty::TyCodeBlock { pub(crate) fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, code_block: CodeBlock, - ) -> CompileResult<(Self, TypeId)> { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - + ) -> Result<(Self, TypeId), ErrorEmitted> { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -22,7 +20,7 @@ impl ty::TyCodeBlock { .iter() .filter_map(|node| { let ctx = ctx.by_ref().scoped(&mut code_block_namespace); - ty::TyAstNode::type_check(ctx, node.clone()).ok(&mut warnings, &mut errors) + ty::TyAstNode::type_check(handler, ctx, node.clone()).ok() }) .collect::>(); @@ -69,8 +67,8 @@ impl ty::TyCodeBlock { let never_decl_opt = ctx .namespace .root() - .resolve_symbol(&never_mod_path, &never_ident) - .value; + .resolve_symbol(&Handler::default(), &never_mod_path, &never_ident) + .ok(); if let Some(ty::TyDecl::EnumDecl(ty::EnumDecl { name, @@ -93,11 +91,17 @@ impl ty::TyCodeBlock { } }); - append!(ctx.unify_with_self(block_type, &span), warnings, errors); + let (warnings, errors) = ctx.unify_with_self(block_type, &span); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } let typed_code_block = ty::TyCodeBlock { contents: evaluated_contents, }; - ok((typed_code_block, block_type), warnings, errors) + Ok((typed_code_block, block_type)) } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index 2af9b8784c5..d3b5add14b9 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -3,9 +3,10 @@ use std::collections::HashSet; use sway_error::error::CompileError; use sway_types::{Ident, Span, Spanned}; +use crate::decl_engine::{DeclEngineInsert, DeclId}; +use sway_error::handler::{ErrorEmitted, Handler}; + use crate::{ - decl_engine::{DeclEngineInsert, DeclId}, - error::*, language::{ parsed::*, ty::{self, TyImplItem, TyTraitItem}, @@ -15,17 +16,15 @@ use crate::{ semantic_analysis::{ declaration::insert_supertraits_into_namespace, AbiMode, TypeCheckContext, }, - CompileResult, ReplaceSelfType, TypeId, TypeInfo, + ReplaceSelfType, TypeId, TypeInfo, }; impl ty::TyAbiDecl { pub(crate) fn type_check( + handler: &Handler, ctx: TypeCheckContext, abi_decl: AbiDeclaration, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let AbiDeclaration { name, interface_surface, @@ -51,17 +50,13 @@ impl ty::TyAbiDecl { // Recursively make the interface surfaces and methods of the // supertraits available to this abi. - check!( - insert_supertraits_into_namespace( - ctx.by_ref(), - self_type, - &supertraits, - &SupertraitOf::Abi(span.clone()) - ), - return err(warnings, errors), - warnings, - errors - ); + insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + self_type, + &supertraits, + &SupertraitOf::Abi(span.clone()), + )?; // Type check the interface surface. let mut new_interface_surface = vec![]; @@ -69,31 +64,28 @@ impl ty::TyAbiDecl { let mut ids: HashSet = HashSet::default(); let error_on_shadowing_superabi_method = - |method_name: &Ident, ctx: &mut TypeCheckContext, errors: &mut Vec| { - if let Some(superabi_impl_method_ref) = ctx - .namespace - .find_method_for_type( - ctx.self_type(), - &[], - &method_name.clone(), - ctx.self_type(), - ctx.type_annotation(), - &Default::default(), - None, - ctx.engines, - false, - ) - .value - { + |method_name: &Ident, ctx: &mut TypeCheckContext| { + if let Ok(superabi_impl_method_ref) = ctx.namespace.find_method_for_type( + &Handler::default(), + ctx.self_type(), + &[], + &method_name.clone(), + ctx.self_type(), + ctx.type_annotation(), + &Default::default(), + None, + ctx.engines, + false, + ) { let superabi_impl_method = ctx.engines.de().get_function(&superabi_impl_method_ref); if let Some(ty::TyDecl::AbiDecl(abi_decl)) = - superabi_impl_method.implementing_type.clone() + superabi_impl_method.implementing_type { - errors.push(CompileError::AbiShadowsSuperAbiMethod { - span: method_name.span().clone(), - superabi: abi_decl.name.clone(), - }) + handler.emit_err(CompileError::AbiShadowsSuperAbiMethod { + span: method_name.span(), + superabi: abi_decl.name, + }); } } }; @@ -103,19 +95,14 @@ impl ty::TyAbiDecl { TraitItem::TraitFn(method) => { // check that a super-trait does not define a method // with the same name as the current interface method - error_on_shadowing_superabi_method(&method.name, &mut ctx, &mut errors); - let method = check!( - ty::TyTraitFn::type_check(ctx.by_ref(), method), - return err(warnings, errors), - warnings, - errors - ); + error_on_shadowing_superabi_method(&method.name, &mut ctx); + let method = ty::TyTraitFn::type_check(handler, ctx.by_ref(), method)?; for param in &method.parameters { if param.is_reference || param.is_mutable { - errors.push(CompileError::RefMutableNotAllowedInContractAbi { + handler.emit_err(CompileError::RefMutableNotAllowedInContractAbi { param_name: param.name.clone(), span: param.name.span(), - }) + }); } } new_interface_surface.push(ty::TyTraitInterfaceItem::TraitFn( @@ -124,66 +111,55 @@ impl ty::TyAbiDecl { method.name.clone() } TraitItem::Constant(const_decl) => { - let const_decl = check!( - ty::TyConstantDecl::type_check(ctx.by_ref(), const_decl.clone(),), - return err(warnings, errors), - warnings, - errors - ); + let const_decl = + ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl.clone())?; let decl_ref = ctx.engines.de().insert(const_decl.clone()); new_interface_surface .push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone())); let const_name = const_decl.call_path.suffix.clone(); - check!( - ctx.insert_symbol( - const_name.clone(), - ty::TyDecl::ConstantDecl(ty::ConstantDecl { - name: const_name.clone(), - decl_id: *decl_ref.id(), - decl_span: const_decl.span.clone() - }) - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol( + handler, + const_name.clone(), + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + name: const_name.clone(), + decl_id: *decl_ref.id(), + decl_span: const_decl.span.clone(), + }), + )?; const_name } }; if !ids.insert(decl_name.clone()) { - errors.push(CompileError::MultipleDefinitionsOfName { + handler.emit_err(CompileError::MultipleDefinitionsOfName { name: decl_name.clone(), span: decl_name.span(), - }) + }); } } // Type check the items. let mut new_items = vec![]; for method in methods.into_iter() { - let method = check!( - ty::TyFunctionDecl::type_check(ctx.by_ref(), method.clone(), false, false), - ty::TyFunctionDecl::error(method.clone()), - warnings, - errors - ); - error_on_shadowing_superabi_method(&method.name, &mut ctx, &mut errors); + let method = + ty::TyFunctionDecl::type_check(handler, ctx.by_ref(), method.clone(), false, false) + .unwrap_or_else(|_| ty::TyFunctionDecl::error(method.clone())); + error_on_shadowing_superabi_method(&method.name, &mut ctx); for param in &method.parameters { if param.is_reference || param.is_mutable { - errors.push(CompileError::RefMutableNotAllowedInContractAbi { + handler.emit_err(CompileError::RefMutableNotAllowedInContractAbi { param_name: param.name.clone(), span: param.name.span(), - }) + }); } } if !ids.insert(method.name.clone()) { - errors.push(CompileError::MultipleDefinitionsOfName { + handler.emit_err(CompileError::MultipleDefinitionsOfName { name: method.name.clone(), span: method.name.span(), - }) + }); } new_items.push(TyTraitItem::Fn(ctx.engines.de().insert(method))); } @@ -199,18 +175,17 @@ impl ty::TyAbiDecl { span, attributes, }; - ok(abi_decl, warnings, errors) + Ok(abi_decl) } pub(crate) fn insert_interface_surface_and_items_into_namespace( &self, + handler: &Handler, self_decl_id: DeclId, ctx: TypeCheckContext, type_id: TypeId, subabi_span: Option, - ) -> CompileResult<()> { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result<(), ErrorEmitted> { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -228,27 +203,26 @@ impl ty::TyAbiDecl { (false, Span::dummy()) }; + let mut error_emitted = None; + for item in interface_surface.iter() { match item { ty::TyTraitInterfaceItem::TraitFn(decl_ref) => { let mut method = decl_engine.get_trait_fn(decl_ref); if look_for_conflicting_abi_methods { // looking for conflicting ABI methods for triangle-like ABI hierarchies - if let Some(superabi_method_ref) = ctx - .namespace - .find_method_for_type( - ctx.self_type(), - &[], - &method.name.clone(), - ctx.self_type(), - ctx.type_annotation(), - &Default::default(), - None, - ctx.engines, - false, - ) - .value - { + if let Ok(superabi_method_ref) = ctx.namespace.find_method_for_type( + &Handler::default(), + ctx.self_type(), + &[], + &method.name.clone(), + ctx.self_type(), + ctx.type_annotation(), + &Default::default(), + None, + ctx.engines, + false, + ) { let superabi_method = ctx.engines.de().get_function(&superabi_method_ref); if let Some(ty::TyDecl::AbiDecl(abi_decl)) = @@ -266,12 +240,14 @@ impl ty::TyAbiDecl { // to place it into Bottom we will encounter // the same method from Top in both Left and Right if self_decl_id != abi_decl.decl_id { - errors.push(CompileError::ConflictingSuperAbiMethods { - span: subabi_span.clone(), - method_name: method.name.to_string(), - superabi1: abi_decl.name.to_string(), - superabi2: self.name.to_string(), - }) + error_emitted = Some(handler.emit_err( + CompileError::ConflictingSuperAbiMethods { + span: subabi_span.clone(), + method_name: method.name.to_string(), + superabi1: abi_decl.name.to_string(), + superabi2: self.name.to_string(), + }, + )) } } } @@ -292,7 +268,8 @@ impl ty::TyAbiDecl { let const_name = const_decl.call_path.suffix.clone(); all_items.push(TyImplItem::Constant(decl_ref.clone())); let const_shadowing_mode = ctx.const_shadowing_mode(); - ctx.namespace.insert_symbol( + let _ = ctx.namespace.insert_symbol( + handler, const_name.clone(), ty::TyDecl::ConstantDecl(ty::ConstantDecl { name: const_name, @@ -311,21 +288,18 @@ impl ty::TyAbiDecl { // check if we inherit the same impl method from different branches // XXX this piece of code can be abstracted out into a closure // and reused for interface methods if the issue of mutable ctx is solved - if let Some(superabi_impl_method_ref) = ctx - .namespace - .find_method_for_type( - ctx.self_type(), - &[], - &method.name.clone(), - ctx.self_type(), - ctx.type_annotation(), - &Default::default(), - None, - ctx.engines, - false, - ) - .value - { + if let Ok(superabi_impl_method_ref) = ctx.namespace.find_method_for_type( + &Handler::default(), + ctx.self_type(), + &[], + &method.name.clone(), + ctx.self_type(), + ctx.type_annotation(), + &Default::default(), + None, + ctx.engines, + false, + ) { let superabi_impl_method = ctx.engines.de().get_function(&superabi_impl_method_ref); if let Some(ty::TyDecl::AbiDecl(abi_decl)) = @@ -333,12 +307,14 @@ impl ty::TyAbiDecl { { // allow the diamond superABI hierarchy if self_decl_id != abi_decl.decl_id { - errors.push(CompileError::ConflictingSuperAbiMethods { - span: subabi_span.clone(), - method_name: method.name.to_string(), - superabi1: abi_decl.name.to_string(), - superabi2: self.name.to_string(), - }) + error_emitted = Some(handler.emit_err( + CompileError::ConflictingSuperAbiMethods { + span: subabi_span.clone(), + method_name: method.name.to_string(), + superabi1: abi_decl.name.to_string(), + superabi2: self.name.to_string(), + }, + )) } } } @@ -363,7 +339,8 @@ impl ty::TyAbiDecl { // these are not actual impl blocks. // We check that a contract method cannot call a contract method // from the same ABI later, during method application typechecking. - ctx.namespace.insert_trait_implementation( + let _ = ctx.namespace.insert_trait_implementation( + &Handler::default(), CallPath::from(self.name.clone()), vec![], type_id, @@ -373,10 +350,10 @@ impl ty::TyAbiDecl { false, ctx.engines, ); - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs index 32f14dea31c..ea1a5627b9c 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs @@ -1,8 +1,10 @@ -use sway_error::warning::{CompileWarning, Warning}; +use sway_error::{ + handler::{ErrorEmitted, Handler}, + warning::{CompileWarning, Warning}, +}; use sway_types::{style::is_screaming_snake_case, Spanned}; use crate::{ - error::*, language::{ parsed::{self, *}, ty::{self, TyConstantDecl}, @@ -13,10 +15,11 @@ use crate::{ }; impl ty::TyConstantDecl { - pub fn type_check(mut ctx: TypeCheckContext, decl: ConstantDeclaration) -> CompileResult { - let mut errors = vec![]; - let mut warnings = vec![]; - + pub fn type_check( + handler: &Handler, + mut ctx: TypeCheckContext, + decl: ConstantDeclaration, + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -30,17 +33,15 @@ impl ty::TyConstantDecl { visibility, } = decl; - type_ascription.type_id = check!( - ctx.resolve_type_with_self( + type_ascription.type_id = ctx + .resolve_type_with_self( + handler, type_ascription.type_id, &type_ascription.span, EnforceTypeArguments::No, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); let mut ctx = ctx .by_ref() @@ -52,10 +53,10 @@ impl ty::TyConstantDecl { let value = match value { Some(value) => { - let result = ty::TyExpression::type_check(ctx.by_ref(), value); + let result = ty::TyExpression::type_check(handler, ctx.by_ref(), value); if !is_screaming_snake_case(name.as_str()) { - warnings.push(CompileWarning { + handler.emit_warn(CompileWarning { span: name.span(), warning_content: Warning::NonScreamingSnakeCaseConstName { name: name.clone(), @@ -63,12 +64,8 @@ impl ty::TyConstantDecl { }) } - let value = check!( - result, - ty::TyExpression::error(name.span(), engines), - warnings, - errors - ); + let value = + result.unwrap_or_else(|_| ty::TyExpression::error(name.span(), engines)); Some(value) } @@ -102,7 +99,7 @@ impl ty::TyConstantDecl { visibility, implementing_type: None, }; - ok(decl, warnings, errors) + Ok(decl) } /// Used to create a stubbed out constant when the constant fails to diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index 27732c4dd82..c5c1a6baa4b 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -1,22 +1,19 @@ +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Named, Spanned}; use crate::{ decl_engine::{DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType}, - error::*, language::{parsed, ty}, semantic_analysis::TypeCheckContext, type_system::*, - CompileResult, }; impl ty::TyDecl { pub(crate) fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, decl: parsed::Declaration, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -28,30 +25,23 @@ impl ty::TyDecl { body, is_mutable, }) => { - type_ascription.type_id = check!( - ctx.resolve_type_with_self( + type_ascription.type_id = ctx + .resolve_type_with_self( + handler, type_ascription.type_id, &type_ascription.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); let mut ctx = ctx .with_type_annotation(type_ascription.type_id) .with_help_text( "Variable declaration's type annotation does not match up \ with the assigned expression's type.", ); - let result = ty::TyExpression::type_check(ctx.by_ref(), body); - let body = check!( - result, - ty::TyExpression::error(name.span(), engines), - warnings, - errors - ); + let result = ty::TyExpression::type_check(handler, ctx.by_ref(), body); + let body = result.unwrap_or_else(|_| ty::TyExpression::error(name.span(), engines)); // Integers are special in the sense that we can't only rely on the type of `body` // to get the type of the variable. The type of the variable *has* to follow @@ -68,78 +58,63 @@ impl ty::TyDecl { return_type, type_ascription, })); - check!( - ctx.insert_symbol(name, typed_var_decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol(handler, name, typed_var_decl.clone())?; typed_var_decl } parsed::Declaration::ConstantDeclaration(decl) => { let span = decl.span.clone(); - let const_decl = check!( - ty::TyConstantDecl::type_check(ctx.by_ref(), decl), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); + let const_decl = match ty::TyConstantDecl::type_check(handler, ctx.by_ref(), decl) { + Ok(res) => res, + Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + }; let typed_const_decl: ty::TyDecl = decl_engine.insert(const_decl.clone()).into(); - check!( - ctx.insert_symbol(const_decl.name().clone(), typed_const_decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol(handler, const_decl.name().clone(), typed_const_decl.clone())?; typed_const_decl } parsed::Declaration::EnumDeclaration(decl) => { let span = decl.span.clone(); - let enum_decl = check!( - ty::TyEnumDecl::type_check(ctx.by_ref(), decl), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); + let enum_decl = match ty::TyEnumDecl::type_check(handler, ctx.by_ref(), decl) { + Ok(res) => res, + Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + }; let call_path = enum_decl.call_path.clone(); let decl: ty::TyDecl = decl_engine.insert(enum_decl).into(); - check!( - ctx.insert_symbol(call_path.suffix, decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol(handler, call_path.suffix, decl.clone())?; decl } parsed::Declaration::FunctionDeclaration(fn_decl) => { let span = fn_decl.span.clone(); let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let fn_decl = check!( - ty::TyFunctionDecl::type_check(ctx.by_ref(), fn_decl, false, false), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); + let fn_decl = match ty::TyFunctionDecl::type_check( + handler, + ctx.by_ref(), + fn_decl, + false, + false, + ) { + Ok(res) => res, + Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + }; let name = fn_decl.name.clone(); let decl: ty::TyDecl = decl_engine.insert(fn_decl).into(); - ctx.insert_symbol(name, decl.clone()); + let _ = ctx.insert_symbol(handler, name, decl.clone()); decl } parsed::Declaration::TraitDeclaration(trait_decl) => { let span = trait_decl.span.clone(); - let mut trait_decl = check!( - ty::TyTraitDecl::type_check(ctx.by_ref(), trait_decl), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); + let mut trait_decl = + match ty::TyTraitDecl::type_check(handler, ctx.by_ref(), trait_decl) { + Ok(res) => res, + Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + }; let name = trait_decl.name.clone(); // save decl_refs for the LSP for supertrait in trait_decl.supertraits.iter_mut() { - ctx.namespace - .resolve_call_path(&supertrait.name) + let _ = ctx + .namespace + .resolve_call_path(handler, &supertrait.name) .cloned() .map(|supertrait_decl| { if let ty::TyDecl::TraitDecl(ty::TraitDecl { @@ -164,22 +139,17 @@ impl ty::TyDecl { .items .iter_mut() .for_each(|item| item.replace_implementing_type(engines, decl.clone())); - check!( - ctx.insert_symbol(name, decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol(handler, name, decl.clone())?; decl } parsed::Declaration::ImplTrait(impl_trait) => { let span = impl_trait.block_span.clone(); - let mut impl_trait = check!( - ty::TyImplTrait::type_check_impl_trait(ctx.by_ref(), impl_trait), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); + let mut impl_trait = + match ty::TyImplTrait::type_check_impl_trait(handler, ctx.by_ref(), impl_trait) + { + Ok(res) => res, + Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + }; // if this ImplTrait implements a trait and not an ABI, // we insert its methods into the context // otherwise, if it implements an ABI, we do not @@ -188,32 +158,28 @@ impl ty::TyDecl { let emp_vec = vec![]; let impl_trait_items = if let Some(ty::TyDecl::TraitDecl { .. }) = ctx .namespace - .resolve_call_path(&impl_trait.trait_name) - .ok(&mut warnings, &mut errors) + .resolve_call_path(&Handler::default(), &impl_trait.trait_name) + .ok() .cloned() { &impl_trait.items } else { &emp_vec }; - check!( - ctx.namespace.insert_trait_implementation( - impl_trait.trait_name.clone(), - impl_trait.trait_type_arguments.clone(), - impl_trait.implementing_for.type_id, - impl_trait_items, - &impl_trait.span, - impl_trait - .trait_decl_ref - .as_ref() - .map(|decl_ref| decl_ref.decl_span().clone()), - false, - engines, - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace.insert_trait_implementation( + handler, + impl_trait.trait_name.clone(), + impl_trait.trait_type_arguments.clone(), + impl_trait.implementing_for.type_id, + impl_trait_items, + &impl_trait.span, + impl_trait + .trait_decl_ref + .as_ref() + .map(|decl_ref| decl_ref.decl_span().clone()), + false, + engines, + )?; let impl_trait_decl: ty::TyDecl = decl_engine.insert(impl_trait.clone()).into(); impl_trait.items.iter_mut().for_each(|item| { item.replace_implementing_type(engines, impl_trait_decl.clone()); @@ -222,30 +188,25 @@ impl ty::TyDecl { } parsed::Declaration::ImplSelf(impl_self) => { let span = impl_self.block_span.clone(); - let mut impl_trait = check!( - ty::TyImplTrait::type_check_impl_self(ctx.by_ref(), impl_self), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); - check!( - ctx.namespace.insert_trait_implementation( - impl_trait.trait_name.clone(), - impl_trait.trait_type_arguments.clone(), - impl_trait.implementing_for.type_id, - &impl_trait.items, - &impl_trait.span, - impl_trait - .trait_decl_ref - .as_ref() - .map(|decl_ref| decl_ref.decl_span().clone()), - true, - engines, - ), - return err(warnings, errors), - warnings, - errors - ); + let mut impl_trait = + match ty::TyImplTrait::type_check_impl_self(handler, ctx.by_ref(), impl_self) { + Ok(val) => val, + Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + }; + ctx.namespace.insert_trait_implementation( + handler, + impl_trait.trait_name.clone(), + impl_trait.trait_type_arguments.clone(), + impl_trait.implementing_for.type_id, + &impl_trait.items, + &impl_trait.span, + impl_trait + .trait_decl_ref + .as_ref() + .map(|decl_ref| decl_ref.decl_span().clone()), + true, + engines, + )?; let impl_trait_decl: ty::TyDecl = decl_engine.insert(impl_trait.clone()).into(); impl_trait.items.iter_mut().for_each(|item| { item.replace_implementing_type(engines, impl_trait_decl.clone()) @@ -254,37 +215,34 @@ impl ty::TyDecl { } parsed::Declaration::StructDeclaration(decl) => { let span = decl.span.clone(); - let decl = check!( - ty::TyStructDecl::type_check(ctx.by_ref(), decl), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); + let decl = match ty::TyStructDecl::type_check(handler, ctx.by_ref(), decl) { + Ok(res) => res, + Err(_) => { + return Ok(ty::TyDecl::ErrorRecovery(span)); + } + }; let call_path = decl.call_path.clone(); let decl: ty::TyDecl = decl_engine.insert(decl).into(); // insert the struct decl into namespace - check!( - ctx.insert_symbol(call_path.suffix, decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol(handler, call_path.suffix, decl.clone())?; decl } parsed::Declaration::AbiDeclaration(abi_decl) => { let span = abi_decl.span.clone(); - let mut abi_decl = check!( - ty::TyAbiDecl::type_check(ctx.by_ref(), abi_decl), - return ok(ty::TyDecl::ErrorRecovery(span), warnings, errors), - warnings, - errors - ); + let mut abi_decl = match ty::TyAbiDecl::type_check(handler, ctx.by_ref(), abi_decl) + { + Ok(res) => res, + Err(_) => { + return Ok(ty::TyDecl::ErrorRecovery(span)); + } + }; let name = abi_decl.name.clone(); // save decl_refs for the LSP for supertrait in abi_decl.supertraits.iter_mut() { - ctx.namespace - .resolve_call_path(&supertrait.name) + let _ = ctx + .namespace + .resolve_call_path(handler, &supertrait.name) .cloned() .map(|supertrait_decl| { if let ty::TyDecl::TraitDecl(ty::TraitDecl { @@ -308,12 +266,7 @@ impl ty::TyDecl { .items .iter_mut() .for_each(|item| item.replace_implementing_type(engines, decl.clone())); - check!( - ctx.insert_symbol(name, decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol(handler, name, decl.clone())?; decl } parsed::Declaration::StorageDeclaration(parsed::StorageDeclaration { @@ -332,20 +285,16 @@ impl ty::TyDecl { .. } in fields { - type_argument.type_id = check!( - ctx.resolve_type_without_self(type_argument.type_id, &name.span(), None), - return err(warnings, errors), - warnings, - errors - ); + type_argument.type_id = ctx.resolve_type_without_self( + handler, + type_argument.type_id, + &name.span(), + None, + )?; let mut ctx = ctx.by_ref().with_type_annotation(type_argument.type_id); - let initializer = check!( - ty::TyExpression::type_check(ctx.by_ref(), initializer), - return err(warnings, errors), - warnings, - errors, - ); + let initializer = + ty::TyExpression::type_check(handler, ctx.by_ref(), initializer)?; fields_buf.push(ty::TyStorageField { name, @@ -366,12 +315,8 @@ impl ty::TyDecl { // if there already was one, return an error that duplicate storage // declarations are not allowed - check!( - ctx.namespace.set_storage_declaration(decl_ref.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace + .set_storage_declaration(handler, decl_ref.clone())?; decl_ref.into() } parsed::Declaration::TypeAliasDeclaration(decl) => { @@ -380,12 +325,15 @@ impl ty::TyDecl { let ty = decl.ty; // Resolve the type that the type alias replaces - let new_ty = check!( - ctx.resolve_type_with_self(ty.type_id, &span, EnforceTypeArguments::Yes, None), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + let new_ty = ctx + .resolve_type_with_self( + handler, + ty.type_id, + &span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); // create the type alias decl using the resolved type above let decl = ty::TyTypeAliasDecl { @@ -404,16 +352,11 @@ impl ty::TyDecl { let decl: ty::TyDecl = decl_engine.insert(decl).into(); // insert the type alias name and decl into namespace - check!( - ctx.insert_symbol(name, decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol(handler, name, decl.clone())?; decl } }; - ok(decl, warnings, errors) + Ok(decl) } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index 89d14c75c1b..4cbcee96464 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -1,15 +1,17 @@ +use sway_error::handler::{ErrorEmitted, Handler}; + use crate::{ - error::*, language::{parsed::*, ty, CallPath}, semantic_analysis::*, type_system::*, }; impl ty::TyEnumDecl { - pub fn type_check(ctx: TypeCheckContext, decl: EnumDeclaration) -> CompileResult { - let mut errors = vec![]; - let mut warnings = vec![]; - + pub fn type_check( + handler: &Handler, + ctx: TypeCheckContext, + decl: EnumDeclaration, + ) -> Result { let EnumDeclaration { name, type_parameters, @@ -26,22 +28,18 @@ impl ty::TyEnumDecl { // Type check the type parameters. This will also insert them into the // current namespace. - let new_type_parameters = check!( - TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters), - return err(warnings, errors), - warnings, - errors - ); + let new_type_parameters = + TypeParameter::type_check_type_params(handler, ctx.by_ref(), type_parameters)?; // type check the variants let mut variants_buf = vec![]; for variant in variants { - variants_buf.push(check!( - ty::TyEnumVariant::type_check(ctx.by_ref(), variant.clone()), - continue, - warnings, - errors - )); + variants_buf.push( + match ty::TyEnumVariant::type_check(handler, ctx.by_ref(), variant.clone()) { + Ok(res) => res, + Err(_) => continue, + }, + ); } let mut call_path: CallPath = name.into(); @@ -56,41 +54,34 @@ impl ty::TyEnumDecl { attributes, visibility, }; - ok(decl, warnings, errors) + Ok(decl) } } impl ty::TyEnumVariant { pub(crate) fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, variant: EnumVariant, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let mut type_argument = variant.type_argument; - type_argument.type_id = check!( - ctx.resolve_type_with_self( + type_argument.type_id = ctx + .resolve_type_with_self( + handler, type_argument.type_id, &type_argument.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); - ok( - ty::TyEnumVariant { - name: variant.name.clone(), - type_argument, - tag: variant.tag, - span: variant.span, - attributes: variant.attributes, - }, - vec![], - errors, - ) + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + Ok(ty::TyEnumVariant { + name: variant.name.clone(), + type_argument, + tag: variant.tag, + span: variant.span, + attributes: variant.attributes, + }) } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 566816138e5..606675c6427 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -3,11 +3,11 @@ mod function_parameter; pub use function_parameter::*; use sway_error::{ error::CompileError, + handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; use crate::{ - error::*, language::{parsed::*, ty, Visibility}, semantic_analysis::*, type_system::*, @@ -16,14 +16,12 @@ use sway_types::{style::is_snake_case, Spanned}; impl ty::TyFunctionDecl { pub fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, fn_decl: FunctionDeclaration, is_method: bool, is_in_impl_self: bool, - ) -> CompileResult { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - + ) -> Result { let FunctionDeclaration { name, body, @@ -42,16 +40,15 @@ impl ty::TyFunctionDecl { // If functions aren't allowed in this location, return an error. if ctx.functions_disallowed() { - errors.push(CompileError::Unimplemented( + return Err(handler.emit_err(CompileError::Unimplemented( "Nested function definitions are not allowed at this time.", span, - )); - return err(warnings, errors); + ))); } // Warn against non-snake case function names. if !is_snake_case(name.as_str()) { - warnings.push(CompileWarning { + handler.emit_warn(CompileWarning { span: name.span(), warning_content: Warning::NonSnakeCaseFunctionName { name: name.clone() }, }) @@ -68,39 +65,37 @@ impl ty::TyFunctionDecl { // Type check the type parameters. This will also insert them into the // current namespace. - let new_type_parameters = check!( - TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters), - return err(warnings, errors), - warnings, - errors - ); + let new_type_parameters = + TypeParameter::type_check_type_params(handler, ctx.by_ref(), type_parameters)?; // type check the function parameters, which will also insert them into the namespace let mut new_parameters = vec![]; + let mut error_emitted = None; for parameter in parameters.into_iter() { - new_parameters.push(check!( - ty::TyFunctionParameter::type_check(ctx.by_ref(), parameter), - continue, - warnings, - errors - )); + new_parameters.push( + match ty::TyFunctionParameter::type_check(handler, ctx.by_ref(), parameter) { + Ok(val) => val, + Err(err) => { + error_emitted = Some(err); + continue; + } + }, + ); } - if !errors.is_empty() { - return err(warnings, errors); + if let Some(err) = error_emitted { + return Err(err); } // type check the return type - return_type.type_id = check!( - ctx.resolve_type_with_self( + return_type.type_id = ctx + .resolve_type_with_self( + handler, return_type.type_id, &return_type.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); // type check the function body // @@ -112,15 +107,12 @@ impl ty::TyFunctionDecl { .with_purity(purity) .with_help_text("Function body's return type does not match up with its return type annotation.") .with_type_annotation(return_type.type_id); - check!( - ty::TyCodeBlock::type_check(ctx, body), + ty::TyCodeBlock::type_check(handler, ctx, body).unwrap_or_else(|_| { ( ty::TyCodeBlock { contents: vec![] }, - type_engine.insert(engines, TypeInfo::ErrorRecovery) - ), - warnings, - errors - ) + type_engine.insert(engines, TypeInfo::ErrorRecovery), + ) + }) }; // gather the return statements @@ -130,12 +122,12 @@ impl ty::TyFunctionDecl { .flat_map(|node| node.gather_return_statements()) .collect(); - check!( - unify_return_statements(ctx.by_ref(), &return_statements, return_type.type_id), - return err(warnings, errors), - warnings, - errors - ); + unify_return_statements( + handler, + ctx.by_ref(), + &return_statements, + return_type.type_id, + )?; let (visibility, is_contract_call) = if is_method { if is_in_impl_self { @@ -147,14 +139,12 @@ impl ty::TyFunctionDecl { (visibility, matches!(ctx.abi_mode(), AbiMode::ImplAbiFn(..))) }; - check!( - return_type - .type_id - .check_type_parameter_bounds(&ctx, &return_type.span, vec![]), - return err(warnings, errors), - warnings, - errors - ); + return_type.type_id.check_type_parameter_bounds( + handler, + &ctx, + &return_type.span, + vec![], + )?; let function_decl = ty::TyFunctionDecl { name, @@ -171,43 +161,43 @@ impl ty::TyFunctionDecl { where_clause, }; - ok(function_decl, warnings, errors) + Ok(function_decl) } } /// Unifies the types of the return statements and the return type of the /// function declaration. fn unify_return_statements( + handler: &Handler, ctx: TypeCheckContext, return_statements: &[&ty::TyExpression], return_type: TypeId, -) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result<(), ErrorEmitted> { let type_engine = ctx.engines.te(); + let mut error_emitted = None; + for stmt in return_statements.iter() { - check!( - CompileResult::from(type_engine.unify_with_self( - ctx.engines(), - stmt.return_type, - return_type, - ctx.self_type(), - &stmt.span, - "Return statement must return the declared function return type.", - None, - )), - continue, - warnings, - errors + let (warnings, errors) = type_engine.unify_with_self( + ctx.engines(), + stmt.return_type, + return_type, + ctx.self_type(), + &stmt.span, + "Return statement must return the declared function return type.", + None, ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + error_emitted = Some(handler.emit_err(err)); + } } - - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } @@ -218,6 +208,7 @@ fn test_function_selector_behavior() { use sway_types::{integer_bits::IntegerBits, Ident, Span}; let engines = Engines::default(); + let handler = Handler::default(); let decl = ty::TyFunctionDecl { purity: Default::default(), name: Ident::new_no_span("foo".into()), @@ -233,10 +224,9 @@ fn test_function_selector_behavior() { where_clause: vec![], }; - let selector_text = match decl.to_selector_name(&engines).value { - Some(value) => value, - _ => panic!("test failure"), - }; + let selector_text = decl + .to_selector_name(&handler, &engines) + .expect("test failure"); assert_eq!(selector_text, "foo()".to_string()); @@ -282,10 +272,9 @@ fn test_function_selector_behavior() { where_clause: vec![], }; - let selector_text = match decl.to_selector_name(&engines).value { - Some(value) => value, - _ => panic!("test failure"), - }; + let selector_text = decl + .to_selector_name(&handler, &engines) + .expect("test failure"); assert_eq!(selector_text, "bar(str[5],u32)".to_string()); } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs index 3f7c91ed239..57e7fb0b26e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs @@ -1,22 +1,21 @@ use crate::{ - error::{err, ok}, language::{parsed::FunctionParameter, ty}, semantic_analysis::TypeCheckContext, type_system::*, - CompileResult, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::Spanned; impl ty::TyFunctionParameter { pub(crate) fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, parameter: FunctionParameter, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -28,34 +27,31 @@ impl ty::TyFunctionParameter { mut type_argument, } = parameter; - type_argument.type_id = check!( - ctx.resolve_type_with_self( + type_argument.type_id = ctx + .resolve_type_with_self( + handler, type_argument.type_id, &type_argument.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); - check!( - type_argument - .type_id - .check_type_parameter_bounds(&ctx, &type_argument.span, vec![]), - return err(warnings, errors), - warnings, - errors - ); + type_argument.type_id.check_type_parameter_bounds( + handler, + &ctx, + &type_argument.span, + vec![], + )?; let mutability = ty::VariableMutability::new_from_ref_mut(is_reference, is_mutable); if mutability == ty::VariableMutability::Mutable { - errors.push(CompileError::MutableParameterNotSupported { - param_name: name.clone(), - span: name.span(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MutableParameterNotSupported { + param_name: name.clone(), + span: name.span(), + }), + ); } let typed_parameter = ty::TyFunctionParameter { @@ -66,18 +62,16 @@ impl ty::TyFunctionParameter { type_argument, }; - insert_into_namespace(ctx, &typed_parameter); + insert_into_namespace(handler, ctx, &typed_parameter); - ok(typed_parameter, warnings, errors) + Ok(typed_parameter) } pub(crate) fn type_check_interface_parameter( + handler: &Handler, mut ctx: TypeCheckContext, parameter: FunctionParameter, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -89,17 +83,15 @@ impl ty::TyFunctionParameter { mut type_argument, } = parameter; - type_argument.type_id = check!( - ctx.resolve_type_with_self( + type_argument.type_id = ctx + .resolve_type_with_self( + handler, type_argument.type_id, &type_argument.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); let typed_parameter = ty::TyFunctionParameter { name, @@ -109,13 +101,18 @@ impl ty::TyFunctionParameter { type_argument, }; - ok(typed_parameter, warnings, errors) + Ok(typed_parameter) } } -fn insert_into_namespace(ctx: TypeCheckContext, typed_parameter: &ty::TyFunctionParameter) { +fn insert_into_namespace( + handler: &Handler, + ctx: TypeCheckContext, + typed_parameter: &ty::TyFunctionParameter, +) { let const_shadowing_mode = ctx.const_shadowing_mode(); - ctx.namespace.insert_symbol( + let _ = ctx.namespace.insert_symbol( + handler, typed_parameter.name.clone(), ty::TyDecl::VariableDecl(Box::new(ty::TyVariableDecl { name: typed_parameter.name.clone(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index f46aba71123..0ff4a83b8a6 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -1,12 +1,14 @@ use std::collections::{BTreeMap, HashMap, HashSet}; -use sway_error::error::{CompileError, InterfaceName}; +use sway_error::{ + error::{CompileError, InterfaceName}, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span, Spanned}; use crate::{ decl_engine::*, engine_threading::*, - error::*, language::{ parsed::*, ty::{self, TyImplItem, TyTraitInterfaceItem, TyTraitItem}, @@ -18,12 +20,10 @@ use crate::{ impl ty::TyImplTrait { pub(crate) fn type_check_impl_trait( + handler: &Handler, mut ctx: TypeCheckContext, impl_trait: ImplTrait, - ) -> CompileResult { - let mut errors = vec![]; - let mut warnings = vec![]; - + ) -> Result { let ImplTrait { impl_type_parameters, trait_name, @@ -47,54 +47,37 @@ impl ty::TyImplTrait { // Type check the type parameters. This will also insert them into the // current namespace. - let new_impl_type_parameters = check!( - TypeParameter::type_check_type_params(ctx.by_ref(), impl_type_parameters), - return err(warnings, errors), - warnings, - errors - ); + let new_impl_type_parameters = + TypeParameter::type_check_type_params(handler, ctx.by_ref(), impl_type_parameters)?; // resolve the types of the trait type arguments for type_arg in trait_type_arguments.iter_mut() { - type_arg.type_id = check!( - ctx.resolve_type_without_self(type_arg.type_id, &type_arg.span, None), - return err(warnings, errors), - warnings, - errors - ); + type_arg.type_id = + ctx.resolve_type_without_self(handler, type_arg.type_id, &type_arg.span, None)?; } // type check the type that we are implementing for - implementing_for.type_id = check!( - ctx.resolve_type_without_self(implementing_for.type_id, &implementing_for.span, None), - return err(warnings, errors), - warnings, - errors - ); + implementing_for.type_id = ctx.resolve_type_without_self( + handler, + implementing_for.type_id, + &implementing_for.span, + None, + )?; // check to see if this type is supported in impl blocks - check!( - type_engine - .get(implementing_for.type_id) - .expect_is_supported_in_impl_blocks_self(&implementing_for.span), - return err(warnings, errors), - warnings, - errors - ); + type_engine + .get(implementing_for.type_id) + .expect_is_supported_in_impl_blocks_self(handler, &implementing_for.span)?; // check for unconstrained type parameters - check!( - check_for_unconstrained_type_parameters( - engines, - &new_impl_type_parameters, - &trait_type_arguments, - implementing_for.type_id, - ), - return err(warnings, errors), - warnings, - errors - ); + check_for_unconstrained_type_parameters( + handler, + engines, + &new_impl_type_parameters, + &trait_type_arguments, + implementing_for.type_id, + )?; // Update the context with the new `self` type. let mut ctx = ctx @@ -104,54 +87,47 @@ impl ty::TyImplTrait { let impl_trait = match ctx .namespace - .resolve_call_path(&trait_name) - .ok(&mut warnings, &mut errors) + .resolve_call_path(handler, &trait_name) + .ok() .cloned() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { let mut trait_decl = decl_engine.get_trait(&decl_id); // monomorphize the trait declaration - check!( - ctx.monomorphize( - &mut trait_decl, - &mut trait_type_arguments, - EnforceTypeArguments::Yes, - &trait_name.span() - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut trait_decl, + &mut trait_type_arguments, + EnforceTypeArguments::Yes, + &trait_name.span(), + )?; // Insert the interface surface and methods from this trait into // the namespace. trait_decl.insert_interface_surface_and_items_into_namespace( + handler, ctx.by_ref(), &trait_name, &trait_type_arguments, implementing_for.type_id, ); - let new_items = check!( - type_check_trait_implementation( - ctx.by_ref(), - &new_impl_type_parameters, - &trait_decl.type_parameters, - &trait_type_arguments, - &trait_decl.supertraits, - &trait_decl.interface_surface, - &trait_decl.items, - &items, - &trait_name, - &trait_decl.span(), - &block_span, - false, - ), - return err(warnings, errors), - warnings, - errors - ); + let new_items = type_check_trait_implementation( + handler, + ctx.by_ref(), + &new_impl_type_parameters, + &trait_decl.type_parameters, + &trait_type_arguments, + &trait_decl.supertraits, + &trait_decl.interface_surface, + &trait_decl.items, + &items, + &trait_name, + &trait_decl.span(), + &block_span, + false, + )?; ty::TyImplTrait { impl_type_parameters: new_impl_type_parameters, trait_name: trait_name.clone(), @@ -178,7 +154,7 @@ impl ty::TyImplTrait { .get(implementing_for.type_id) .eq(&TypeInfo::Contract, engines) { - errors.push(CompileError::ImplAbiForNonContract { + handler.emit_err(CompileError::ImplAbiForNonContract { span: implementing_for.span(), ty: engines.help_out(implementing_for.type_id).to_string(), }); @@ -188,32 +164,29 @@ impl ty::TyImplTrait { // Insert the interface surface and methods from this trait into // the namespace. - abi.insert_interface_surface_and_items_into_namespace( + let _ = abi.insert_interface_surface_and_items_into_namespace( + handler, decl_id, ctx.by_ref(), implementing_for.type_id, None, ); - let new_items = check!( - type_check_trait_implementation( - ctx.by_ref(), - &[], // this is empty because abi definitions don't support generics, - &[], // this is empty because abi definitions don't support generics, - &[], // this is empty because abi definitions don't support generics, - &abi.supertraits, - &abi.interface_surface, - &abi.items, - &items, - &trait_name, - &abi.span(), - &block_span, - true - ), - return err(warnings, errors), - warnings, - errors - ); + let new_items = type_check_trait_implementation( + handler, + ctx.by_ref(), + &[], // this is empty because abi definitions don't support generics, + &[], // this is empty because abi definitions don't support generics, + &[], // this is empty because abi definitions don't support generics, + &abi.supertraits, + &abi.interface_surface, + &abi.items, + &items, + &trait_name, + &abi.span(), + &block_span, + true, + )?; ty::TyImplTrait { impl_type_parameters: vec![], // this is empty because abi definitions don't support generics trait_name, @@ -225,23 +198,20 @@ impl ty::TyImplTrait { } } Some(_) | None => { - errors.push(CompileError::UnknownTrait { + return Err(handler.emit_err(CompileError::UnknownTrait { name: trait_name.suffix.clone(), span: trait_name.span(), - }); - return err(warnings, errors); + })); } }; - ok(impl_trait, warnings, errors) + Ok(impl_trait) } pub(crate) fn type_check_impl_self( + handler: &Handler, ctx: TypeCheckContext, impl_self: ImplSelf, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let ImplSelf { impl_type_parameters, mut implementing_for, @@ -272,54 +242,37 @@ impl ty::TyImplTrait { // Type check the type parameters. This will also insert them into the // current namespace. - let new_impl_type_parameters = check!( - TypeParameter::type_check_type_params(ctx.by_ref(), impl_type_parameters), - return err(warnings, errors), - warnings, - errors - ); + let new_impl_type_parameters = + TypeParameter::type_check_type_params(handler, ctx.by_ref(), impl_type_parameters)?; // type check the type that we are implementing for - implementing_for.type_id = check!( - ctx.resolve_type_without_self(implementing_for.type_id, &implementing_for.span, None), - return err(warnings, errors), - warnings, - errors - ); + implementing_for.type_id = ctx.resolve_type_without_self( + handler, + implementing_for.type_id, + &implementing_for.span, + None, + )?; // check to see if this type is supported in impl blocks - check!( - type_engine - .get(implementing_for.type_id) - .expect_is_supported_in_impl_blocks_self(&implementing_for.span), - return err(warnings, errors), - warnings, - errors - ); + type_engine + .get(implementing_for.type_id) + .expect_is_supported_in_impl_blocks_self(handler, &implementing_for.span)?; // check for unconstrained type parameters - check!( - check_for_unconstrained_type_parameters( - engines, - &new_impl_type_parameters, - &[], - implementing_for.type_id, - ), - return err(warnings, errors), - warnings, - errors - ); - - check!( - implementing_for.type_id.check_type_parameter_bounds( - &ctx, - &implementing_for.span, - vec![] - ), - return err(warnings, errors), - warnings, - errors - ); + check_for_unconstrained_type_parameters( + handler, + engines, + &new_impl_type_parameters, + &[], + implementing_for.type_id, + )?; + + implementing_for.type_id.check_type_parameter_bounds( + handler, + &ctx, + &implementing_for.span, + vec![], + )?; let mut ctx = ctx .with_self_type(implementing_for.type_id) @@ -333,51 +286,58 @@ impl ty::TyImplTrait { _ => None, }; if let Some(self_decl) = self_decl { - ctx.insert_symbol(Ident::new_no_span("Self".to_string()), self_decl); + let _ = ctx.insert_symbol(handler, Ident::new_no_span("Self".to_string()), self_decl); } // type check the items inside of the impl block let mut new_items = vec![]; + let mut error_emitted = None; for item in items.into_iter() { match item { ImplItem::Fn(fn_decl) => { - let fn_decl = check!( - ty::TyFunctionDecl::type_check(ctx.by_ref(), fn_decl, true, true), - continue, - warnings, - errors - ); + let fn_decl = match ty::TyFunctionDecl::type_check( + handler, + ctx.by_ref(), + fn_decl, + true, + true, + ) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }; new_items.push(TyImplItem::Fn(decl_engine.insert(fn_decl))); } ImplItem::Constant(const_decl) => { - let const_decl = check!( - ty::TyConstantDecl::type_check(ctx.by_ref(), const_decl), - continue, - warnings, - errors - ); + let const_decl = + match ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }; let decl_ref = decl_engine.insert(const_decl); new_items.push(TyImplItem::Constant(decl_ref.clone())); - check!( - ctx.insert_symbol( - decl_ref.name().clone(), - ty::TyDecl::ConstantDecl(ty::ConstantDecl { - name: decl_ref.name().clone(), - decl_id: *decl_ref.id(), - decl_span: decl_ref.span().clone() - }) - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol( + handler, + decl_ref.name().clone(), + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + name: decl_ref.name().clone(), + decl_id: *decl_ref.id(), + decl_span: decl_ref.span().clone(), + }), + )?; } } } - if !errors.is_empty() { - return err(warnings, errors); + + if let Some(err) = error_emitted { + return Err(err); } let impl_trait = ty::TyImplTrait { @@ -389,12 +349,13 @@ impl ty::TyImplTrait { items: new_items, implementing_for, }; - ok(impl_trait, warnings, errors) + Ok(impl_trait) } } #[allow(clippy::too_many_arguments)] fn type_check_trait_implementation( + handler: &Handler, mut ctx: TypeCheckContext, impl_type_parameters: &[TypeParameter], trait_type_parameters: &[TypeParameter], @@ -407,44 +368,33 @@ fn type_check_trait_implementation( trait_decl_span: &Span, block_span: &Span, is_contract: bool, -) -> CompileResult> { - let mut errors = vec![]; - let mut warnings = vec![]; - +) -> Result, ErrorEmitted> { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); let self_type = ctx.self_type(); // Check to see if the type that we are implementing for implements the // supertraits of this trait. - check!( - ctx.namespace - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - self_type, - &trait_supertraits - .iter() - .map(|x| x.into()) - .collect::>(), - block_span, - engines, - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace + .implemented_traits + .check_if_trait_constraints_are_satisfied_for_type( + handler, + self_type, + &trait_supertraits + .iter() + .map(|x| x.into()) + .collect::>(), + block_span, + engines, + )?; for (type_arg, type_param) in trait_type_arguments.iter().zip(trait_type_parameters) { - check!( - type_arg.type_id.check_type_parameter_bounds( - &ctx, - &type_arg.span(), - type_param.trait_constraints.clone() - ), - return err(warnings, errors), - warnings, - errors - ); + type_arg.type_id.check_type_parameter_bounds( + handler, + &ctx, + &type_arg.span(), + type_param.trait_constraints.clone(), + )?; } // This map keeps track of the remaining functions in the interface surface @@ -476,13 +426,11 @@ fn type_check_trait_implementation( // namespace and not a real impl block defined by the user. if !trait_supertraits.is_empty() { // Gather the supertrait "stub_method_refs" and "impld_method_refs". - let (this_supertrait_stub_method_refs, this_supertrait_impld_method_refs) = check!( - handle_supertraits(ctx.by_ref(), trait_supertraits), - return err(warnings, errors), - warnings, - errors - ); - ctx.namespace.insert_trait_implementation( + let (this_supertrait_stub_method_refs, this_supertrait_impld_method_refs) = + handle_supertraits(handler, ctx.by_ref(), trait_supertraits)?; + + let _ = ctx.namespace.insert_trait_implementation( + &Handler::default(), trait_name.clone(), trait_type_arguments.to_vec(), self_type, @@ -520,20 +468,17 @@ fn type_check_trait_implementation( for item in impl_items { match item { ImplItem::Fn(impl_method) => { - let impl_method = check!( - type_check_impl_method( - ctx.by_ref(), - impl_type_parameters, - impl_method, - trait_name, - is_contract, - &impld_item_refs, - &method_checklist - ), - ty::TyFunctionDecl::error(impl_method.clone()), - warnings, - errors - ); + let impl_method = type_check_impl_method( + handler, + ctx.by_ref(), + impl_type_parameters, + impl_method, + trait_name, + is_contract, + &impld_item_refs, + &method_checklist, + ) + .unwrap_or_else(|_| ty::TyFunctionDecl::error(impl_method.clone())); // Remove this method from the checklist. let name = impl_method.name.clone(); @@ -544,19 +489,16 @@ fn type_check_trait_implementation( impld_item_refs.insert(name, TyTraitItem::Fn(decl_ref)); } ImplItem::Constant(const_decl) => { - let const_decl = check!( - type_check_const_decl( - ctx.by_ref(), - const_decl, - trait_name, - is_contract, - &impld_item_refs, - &constant_checklist - ), - ty::TyConstantDecl::error(ctx.engines(), const_decl.clone()), - warnings, - errors - ); + let const_decl = type_check_const_decl( + handler, + ctx.by_ref(), + const_decl, + trait_name, + is_contract, + &impld_item_refs, + &constant_checklist, + ) + .unwrap_or_else(|_| ty::TyConstantDecl::error(ctx.engines(), const_decl.clone())); // Remove this constant from the checklist. let name = const_decl.call_path.suffix.clone(); @@ -617,37 +559,45 @@ fn type_check_trait_implementation( } } + let mut error_emitted = None; + // check that the implementation checklist is complete if !method_checklist.is_empty() { - errors.push(CompileError::MissingInterfaceSurfaceMethods { - span: block_span.clone(), - missing_functions: method_checklist - .into_keys() - .map(|ident| ident.as_str().to_string()) - .collect::>() - .join("\n"), - }); + error_emitted = Some( + handler.emit_err(CompileError::MissingInterfaceSurfaceMethods { + span: block_span.clone(), + missing_functions: method_checklist + .into_keys() + .map(|ident| ident.as_str().to_string()) + .collect::>() + .join("\n"), + }), + ); } if !constant_checklist.is_empty() { - errors.push(CompileError::MissingInterfaceSurfaceConstants { - span: block_span.clone(), - missing_constants: constant_checklist - .into_keys() - .map(|ident| ident.as_str().to_string()) - .collect::>() - .join("\n"), - }); + error_emitted = Some( + handler.emit_err(CompileError::MissingInterfaceSurfaceConstants { + span: block_span.clone(), + missing_constants: constant_checklist + .into_keys() + .map(|ident| ident.as_str().to_string()) + .collect::>() + .join("\n"), + }), + ); } - if errors.is_empty() { - ok(all_items_refs, warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(all_items_refs) } } +#[allow(clippy::too_many_arguments)] fn type_check_impl_method( + handler: &Handler, mut ctx: TypeCheckContext, impl_type_parameters: &[TypeParameter], impl_method: &FunctionDeclaration, @@ -655,10 +605,7 @@ fn type_check_impl_method( is_contract: bool, impld_item_refs: &ItemMap, method_checklist: &BTreeMap, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let self_type = ctx.self_type(); @@ -677,32 +624,30 @@ fn type_check_impl_method( }; // type check the function declaration - let mut impl_method = check!( - ty::TyFunctionDecl::type_check(ctx.by_ref(), impl_method.clone(), true, false), - return err(warnings, errors), - warnings, - errors - ); + let mut impl_method = + ty::TyFunctionDecl::type_check(handler, ctx.by_ref(), impl_method.clone(), true, false)?; // Ensure that there aren't multiple definitions of this function impl'd if impld_item_refs.contains_key(&impl_method.name.clone()) { - errors.push(CompileError::MultipleDefinitionsOfFunction { - name: impl_method.name.clone(), - span: impl_method.name.span(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MultipleDefinitionsOfFunction { + name: impl_method.name.clone(), + span: impl_method.name.span(), + }), + ); } // Ensure that the method checklist contains this function. let mut impl_method_signature = match method_checklist.get(&impl_method.name) { Some(trait_fn) => trait_fn.clone(), None => { - errors.push(CompileError::FunctionNotAPartOfInterfaceSurface { - name: impl_method.name.clone(), - interface_name: interface_name(), - span: impl_method.name.span(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::FunctionNotAPartOfInterfaceSurface { + name: impl_method.name.clone(), + interface_name: interface_name(), + span: impl_method.name.span(), + }), + ); } }; @@ -714,7 +659,7 @@ fn type_check_impl_method( // ensure this fn decl's parameters and signature lines up with the one // in the trait if impl_method.parameters.len() != impl_method_signature.parameters.len() { - errors.push( + return Err(handler.emit_err( CompileError::IncorrectNumberOfInterfaceSurfaceFunctionParameters { span: impl_method.parameters_span(), fn_name: impl_method.name.clone(), @@ -722,10 +667,11 @@ fn type_check_impl_method( num_parameters: impl_method_signature.parameters.len(), provided_parameters: impl_method.parameters.len(), }, - ); - return err(warnings, errors); + )); } + let mut error_emitted = None; + // unify the types from the parameters of the function declaration // with the parameters of the function signature for (impl_method_signature_param, impl_method_param) in impl_method_signature @@ -737,36 +683,42 @@ fn type_check_impl_method( // implement trait constraint solver */ // Check if we have a non-ref mutable argument. That's not allowed. if impl_method_signature_param.is_mutable && !impl_method_signature_param.is_reference { - errors.push(CompileError::MutableParameterNotSupported { - param_name: impl_method_signature.name.clone(), - span: impl_method_signature.name.span(), - }); + error_emitted = Some( + handler.emit_err(CompileError::MutableParameterNotSupported { + param_name: impl_method_signature.name.clone(), + span: impl_method_signature.name.span(), + }), + ); } // check if reference / mutability of the parameters is incompatible if impl_method_param.is_mutable != impl_method_signature_param.is_mutable || impl_method_param.is_reference != impl_method_signature_param.is_reference { - errors.push(CompileError::ParameterRefMutabilityMismatch { - span: impl_method_param.mutability_span.clone(), - }); + error_emitted = Some( + handler.emit_err(CompileError::ParameterRefMutabilityMismatch { + span: impl_method_param.mutability_span.clone(), + }), + ); } if !type_engine.get(impl_method_param.type_argument.type_id).eq( &type_engine.get(impl_method_signature_param.type_argument.type_id), engines, ) { - errors.push(CompileError::MismatchedTypeInInterfaceSurface { - interface_name: interface_name(), - span: impl_method_param.type_argument.span.clone(), - decl_type: "function".to_string(), - given: engines - .help_out(impl_method_param.type_argument.type_id) - .to_string(), - expected: engines - .help_out(impl_method_signature_param.type_argument.type_id) - .to_string(), - }); + error_emitted = Some( + handler.emit_err(CompileError::MismatchedTypeInInterfaceSurface { + interface_name: interface_name(), + span: impl_method_param.type_argument.span.clone(), + decl_type: "function".to_string(), + given: engines + .help_out(impl_method_param.type_argument.type_id) + .to_string(), + expected: engines + .help_out(impl_method_signature_param.type_argument.type_id) + .to_string(), + }), + ); continue; } } @@ -774,21 +726,23 @@ fn type_check_impl_method( // check to see if the purity of the function declaration is the same // as the purity of the function signature if impl_method.purity != impl_method_signature.purity { - errors.push(if impl_method_signature.purity == Purity::Pure { - CompileError::TraitDeclPureImplImpure { - fn_name: impl_method.name.clone(), - interface_name: interface_name(), - attrs: impl_method.purity.to_attribute_syntax(), - span: impl_method.span.clone(), - } - } else { - CompileError::TraitImplPurityMismatch { - fn_name: impl_method.name.clone(), - interface_name: interface_name(), - attrs: impl_method_signature.purity.to_attribute_syntax(), - span: impl_method.span.clone(), - } - }); + error_emitted = Some( + handler.emit_err(if impl_method_signature.purity == Purity::Pure { + CompileError::TraitDeclPureImplImpure { + fn_name: impl_method.name.clone(), + interface_name: interface_name(), + attrs: impl_method.purity.to_attribute_syntax(), + span: impl_method.span.clone(), + } + } else { + CompileError::TraitImplPurityMismatch { + fn_name: impl_method.name.clone(), + interface_name: interface_name(), + attrs: impl_method_signature.purity.to_attribute_syntax(), + span: impl_method.span.clone(), + } + }), + ); } // check there is no mismatch of payability attributes @@ -800,22 +754,22 @@ fn type_check_impl_method( (true, false) => // implementation does not have payable attribute { - errors.push(CompileError::TraitImplPayabilityMismatch { + error_emitted = Some(handler.emit_err(CompileError::TraitImplPayabilityMismatch { fn_name: impl_method.name.clone(), interface_name: interface_name(), missing_impl_attribute: true, span: impl_method.span.clone(), - }); + })); } (false, true) => // implementation has extra payable attribute, not mentioned by signature { - errors.push(CompileError::TraitImplPayabilityMismatch { + error_emitted = Some(handler.emit_err(CompileError::TraitImplPayabilityMismatch { fn_name: impl_method.name.clone(), interface_name: interface_name(), missing_impl_attribute: false, span: impl_method.span.clone(), - }); + })); } (true, true) | (false, false) => (), // no payability mismatch } @@ -824,16 +778,17 @@ fn type_check_impl_method( &type_engine.get(impl_method_signature.return_type.type_id), engines, ) { - errors.push(CompileError::MismatchedTypeInInterfaceSurface { - interface_name: interface_name(), - span: impl_method.return_type.span.clone(), - decl_type: "function".to_string(), - expected: engines - .help_out(impl_method_signature.return_type) - .to_string(), - given: engines.help_out(impl_method.return_type).to_string(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MismatchedTypeInInterfaceSurface { + interface_name: interface_name(), + span: impl_method.return_type.span.clone(), + decl_type: "function".to_string(), + expected: engines + .help_out(impl_method_signature.return_type) + .to_string(), + given: engines.help_out(impl_method.return_type).to_string(), + }), + ); } // We need to add impl type parameters to the method's type parameters @@ -858,24 +813,22 @@ fn type_check_impl_method( .collect::>(), ); - if errors.is_empty() { - ok(impl_method, warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(impl_method) } } fn type_check_const_decl( + handler: &Handler, mut ctx: TypeCheckContext, const_decl: &ConstantDeclaration, trait_name: &CallPath, is_contract: bool, impld_constant_ids: &ItemMap, constant_checklist: &BTreeMap, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let self_type = ctx.self_type(); @@ -894,34 +847,31 @@ fn type_check_const_decl( }; // type check the constant declaration - let const_decl = check!( - ty::TyConstantDecl::type_check(ctx.by_ref(), const_decl.clone()), - return err(warnings, errors), - warnings, - errors - ); + let const_decl = ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl.clone())?; let const_name = const_decl.call_path.suffix.clone(); // Ensure that there aren't multiple definitions of this constant if impld_constant_ids.contains_key(&const_name) { - errors.push(CompileError::MultipleDefinitionsOfConstant { - name: const_name.clone(), - span: const_name.span(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MultipleDefinitionsOfConstant { + name: const_name.clone(), + span: const_name.span(), + }), + ); } // Ensure that the constant checklist contains this constant. let mut const_decl_signature = match constant_checklist.get(&const_name) { Some(const_decl) => const_decl.clone(), None => { - errors.push(CompileError::ConstantNotAPartOfInterfaceSurface { - name: const_name.clone(), - interface_name: interface_name(), - span: const_name.span(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::ConstantNotAPartOfInterfaceSurface { + name: const_name.clone(), + interface_name: interface_name(), + span: const_name.span(), + }), + ); } }; @@ -935,25 +885,22 @@ fn type_check_const_decl( &type_engine.get(const_decl_signature.type_ascription.type_id), engines, ) { - errors.push(CompileError::MismatchedTypeInInterfaceSurface { - interface_name: interface_name(), - span: const_decl.span.clone(), - decl_type: "constant".to_string(), - given: engines - .help_out(const_decl.type_ascription.type_id) - .to_string(), - expected: engines - .help_out(const_decl_signature.type_ascription.type_id) - .to_string(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MismatchedTypeInInterfaceSurface { + interface_name: interface_name(), + span: const_decl.span.clone(), + decl_type: "constant".to_string(), + given: engines + .help_out(const_decl.type_ascription.type_id) + .to_string(), + expected: engines + .help_out(const_decl_signature.type_ascription.type_id) + .to_string(), + }), + ); } - if errors.is_empty() { - ok(const_decl, warnings, errors) - } else { - err(warnings, errors) - } + Ok(const_decl) } /// Given an array of [TypeParameter] `type_parameters`, checks to see if any of @@ -991,14 +938,12 @@ fn type_check_const_decl( /// } /// ``` fn check_for_unconstrained_type_parameters( + handler: &Handler, engines: &Engines, type_parameters: &[TypeParameter], trait_type_arguments: &[TypeArgument], self_type: TypeId, -) -> CompileResult<()> { - let warnings = vec![]; - let mut errors = vec![]; - +) -> Result<(), ErrorEmitted> { // create a list of defined generics, with the generic and a span let mut defined_generics: HashMap<_, _> = HashMap::from_iter( type_parameters @@ -1027,51 +972,54 @@ fn check_for_unconstrained_type_parameters( defined_generics.remove(&generic); } + let mut error_emitted = None; // create an error for all of the leftover generics for (k, v) in defined_generics.into_iter() { - errors.push(CompileError::UnconstrainedGenericParameter { - ty: format!("{k}"), - span: v, - }); + error_emitted = Some( + handler.emit_err(CompileError::UnconstrainedGenericParameter { + ty: format!("{k}"), + span: v, + }), + ); } - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } fn handle_supertraits( + handler: &Handler, mut ctx: TypeCheckContext, supertraits: &[Supertrait], -) -> CompileResult<(InterfaceItemMap, ItemMap)> { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - +) -> Result<(InterfaceItemMap, ItemMap), ErrorEmitted> { let decl_engine = ctx.engines.de(); let mut interface_surface_item_ids: InterfaceItemMap = BTreeMap::new(); let mut impld_item_refs: ItemMap = BTreeMap::new(); let self_type = ctx.self_type(); + let mut error_emitted = None; + for supertrait in supertraits.iter() { // Right now we don't have the ability to support defining a supertrait // using a callpath directly, so we check to see if the user has done // this and we disallow it. if !supertrait.name.prefixes.is_empty() { - errors.push(CompileError::UnimplementedWithHelp( + error_emitted = Some(handler.emit_err(CompileError::UnimplementedWithHelp( "Using module paths to define supertraits is not supported yet.", "try importing the trait with a \"use\" statement instead", supertrait.span(), - )); + ))); continue; } match ctx .namespace - .resolve_call_path(&supertrait.name) - .ok(&mut warnings, &mut errors) + .resolve_call_path(handler, &supertrait.name) + .ok() .cloned() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { @@ -1080,10 +1028,10 @@ fn handle_supertraits( // Right now we don't parse type arguments for supertraits, so // we should give this error message to users. if !trait_decl.type_parameters.is_empty() { - errors.push(CompileError::Unimplemented( + error_emitted = Some(handler.emit_err(CompileError::Unimplemented( "Using generic traits as supertraits is not supported yet.", supertrait.name.span(), - )); + ))); continue; } @@ -1100,32 +1048,32 @@ fn handle_supertraits( // Retrieve the interface surfaces and implemented methods for // the supertraits of this type. - let (next_interface_supertrait_decl_refs, next_these_supertrait_decl_refs) = check!( - handle_supertraits(ctx.by_ref(), &trait_decl.supertraits), - continue, - warnings, - errors - ); + let (next_interface_supertrait_decl_refs, next_these_supertrait_decl_refs) = + match handle_supertraits(handler, ctx.by_ref(), &trait_decl.supertraits) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }; interface_surface_item_ids.extend(next_interface_supertrait_decl_refs); impld_item_refs.extend(next_these_supertrait_decl_refs); } Some(ty::TyDecl::AbiDecl { .. }) => { // we allow ABIs as superABIs now } - _ => errors.push(CompileError::TraitNotFound { - name: supertrait.name.to_string(), - span: supertrait.name.span(), - }), + _ => { + error_emitted = Some(handler.emit_err(CompileError::TraitNotFound { + name: supertrait.name.to_string(), + span: supertrait.name.span(), + })) + } } } - if errors.is_empty() { - ok( - (interface_surface_item_ids, impld_item_refs), - warnings, - errors, - ) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok((interface_surface_item_ids, impld_item_refs)) } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs index 7cf30058675..bfa9975814e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs @@ -1,5 +1,4 @@ use crate::{ - error::*, fuel_prelude::fuel_tx::StorageSlot, ir_generation::{ const_eval::compile_constant_expression_to_constant, storage::serialize_to_storage_slots, @@ -8,19 +7,23 @@ use crate::{ metadata::MetadataManager, Engines, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_ir::{Context, Module}; use sway_types::state::StateIndex; impl ty::TyStorageDecl { pub(crate) fn get_initialized_storage_slots( &self, + handler: &Handler, engines: &Engines, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, - ) -> CompileResult> { - let mut errors = vec![]; + ) -> Result, ErrorEmitted> { + let mut error_emitted = None; let storage_slots = self .fields .iter() @@ -34,13 +37,17 @@ impl ty::TyStorageDecl { &StateIndex::new(i), ) }) - .filter_map(|s| s.map_err(|e| errors.push(e)).ok()) + .filter_map(|s| { + s.map_err(|e| error_emitted = Some(handler.emit_err(e))) + .ok() + }) .flatten() .collect::>(); - match errors.is_empty() { - true => ok(storage_slots, vec![], vec![]), - false => err(vec![], errors), + if let Some(err) = error_emitted { + Err(err) + } else { + Ok(storage_slots) } } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 7fe8730a26b..af2dc7021c4 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -1,5 +1,6 @@ +use sway_error::handler::{ErrorEmitted, Handler}; + use crate::{ - error::*, language::{parsed::*, ty, CallPath}, semantic_analysis::*, type_system::*, @@ -7,12 +8,10 @@ use crate::{ impl ty::TyStructDecl { pub(crate) fn type_check( + handler: &Handler, ctx: TypeCheckContext, decl: StructDeclaration, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let StructDeclaration { name, fields, @@ -29,22 +28,13 @@ impl ty::TyStructDecl { // Type check the type parameters. This will also insert them into the // current namespace. - let new_type_parameters = check!( - TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters), - return err(warnings, errors), - warnings, - errors - ); + let new_type_parameters = + TypeParameter::type_check_type_params(handler, ctx.by_ref(), type_parameters)?; // type check the fields let mut new_fields = vec![]; for field in fields.into_iter() { - new_fields.push(check!( - ty::TyStructField::type_check(ctx.by_ref(), field), - return err(warnings, errors), - warnings, - errors - )); + new_fields.push(ty::TyStructField::type_check(handler, ctx.by_ref(), field)?); } let mut path: CallPath = name.into(); @@ -60,34 +50,34 @@ impl ty::TyStructDecl { attributes, }; - ok(decl, warnings, errors) + Ok(decl) } } impl ty::TyStructField { - pub(crate) fn type_check(mut ctx: TypeCheckContext, field: StructField) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn type_check( + handler: &Handler, + mut ctx: TypeCheckContext, + field: StructField, + ) -> Result { let type_engine = ctx.engines.te(); let mut type_argument = field.type_argument; - type_argument.type_id = check!( - ctx.resolve_type_with_self( + type_argument.type_id = ctx + .resolve_type_with_self( + handler, type_argument.type_id, &type_argument.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery)); let field = ty::TyStructField { name: field.name, span: field.span, type_argument, attributes: field.attributes, }; - ok(field, warnings, errors) + Ok(field) } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs index cc00ba89c34..cd9c597b041 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs @@ -1,8 +1,8 @@ use sway_error::error::CompileError; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Span, Spanned}; use crate::{ - error::*, language::{parsed, ty}, semantic_analysis::TypeCheckContext, EnforceTypeArguments, TypeId, @@ -17,33 +17,33 @@ pub enum SupertraitOf { /// Recursively insert the interface surfaces and methods from supertraits to /// the given namespace. pub(crate) fn insert_supertraits_into_namespace( + handler: &Handler, mut ctx: TypeCheckContext, type_id: TypeId, supertraits: &[parsed::Supertrait], supertraits_of: &SupertraitOf, -) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result<(), ErrorEmitted> { let decl_engine = ctx.engines.de(); + let mut error_emitted = None; + for supertrait in supertraits.iter() { // Right now we don't have the ability to support defining a supertrait // using a callpath directly, so we check to see if the user has done // this and we disallow it. if !supertrait.name.prefixes.is_empty() { - errors.push(CompileError::UnimplementedWithHelp( + error_emitted = Some(handler.emit_err(CompileError::UnimplementedWithHelp( "Using module paths to define supertraits is not supported yet.", "try importing the trait with a \"use\" statement instead", supertrait.span(), - )); + ))); continue; } let decl = ctx .namespace - .resolve_call_path(&supertrait.name) - .ok(&mut warnings, &mut errors) + .resolve_call_path(handler, &supertrait.name) + .ok() .cloned(); match (decl.clone(), supertraits_of) { @@ -54,10 +54,10 @@ pub(crate) fn insert_supertraits_into_namespace( // Right now we don't parse type arguments for supertraits, so // we should give this error message to users. if !trait_decl.type_parameters.is_empty() { - errors.push(CompileError::Unimplemented( + error_emitted = Some(handler.emit_err(CompileError::Unimplemented( "Using generic traits as supertraits is not supported yet.", supertrait.name.span(), - )); + ))); continue; } @@ -65,21 +65,24 @@ pub(crate) fn insert_supertraits_into_namespace( let mut type_arguments = vec![]; // Monomorphize the trait declaration. - check!( - ctx.monomorphize( - &mut trait_decl, - &mut type_arguments, - EnforceTypeArguments::Yes, - &supertrait.name.span() - ), - continue, - warnings, - errors - ); + match ctx.monomorphize( + handler, + &mut trait_decl, + &mut type_arguments, + EnforceTypeArguments::Yes, + &supertrait.name.span(), + ) { + Ok(_) => {} + Err(err) => { + error_emitted = Some(err); + continue; + } + } // Insert the interface surface and methods from this trait into // the namespace. trait_decl.insert_interface_surface_and_items_into_namespace( + handler, ctx.by_ref(), &supertrait.name, &type_arguments, @@ -88,17 +91,19 @@ pub(crate) fn insert_supertraits_into_namespace( // Recurse to insert versions of interfaces and methods of the // *super* supertraits. - check!( - insert_supertraits_into_namespace( - ctx.by_ref(), - type_id, - &trait_decl.supertraits, - &SupertraitOf::Trait - ), - continue, - warnings, - errors - ); + match insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + type_id, + &trait_decl.supertraits, + &SupertraitOf::Trait, + ) { + Ok(_) => {} + Err(err) => { + error_emitted = Some(err); + continue; + } + } } // an ABI can only be a superABI of an ABI ( @@ -108,47 +113,54 @@ pub(crate) fn insert_supertraits_into_namespace( let abi_decl = decl_engine.get_abi(&decl_id); // Insert the interface surface and methods from this ABI into // the namespace. - check!( - abi_decl.insert_interface_surface_and_items_into_namespace( - decl_id, - ctx.by_ref(), - type_id, - Some(subabi_span.clone()) - ), - continue, - warnings, - errors - ); + match abi_decl.insert_interface_surface_and_items_into_namespace( + handler, + decl_id, + ctx.by_ref(), + type_id, + Some(subabi_span.clone()), + ) { + Ok(_) => {} + Err(err) => { + error_emitted = Some(err); + continue; + } + } // Recurse to insert versions of interfaces and methods of the // *super* superABIs. - check!( - insert_supertraits_into_namespace( - ctx.by_ref(), - type_id, - &abi_decl.supertraits, - &SupertraitOf::Abi(subabi_span.clone()) - ), - continue, - warnings, - errors - ); + + match insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + type_id, + &abi_decl.supertraits, + &SupertraitOf::Abi(subabi_span.clone()), + ) { + Ok(_) => {} + Err(err) => { + error_emitted = Some(err); + continue; + } + } } // an ABI cannot be a supertrait of a trait (Some(ty::TyDecl::AbiDecl { .. }), SupertraitOf::Trait) => { - errors.push(CompileError::AbiAsSupertrait { + error_emitted = Some(handler.emit_err(CompileError::AbiAsSupertrait { span: supertrait.name.span().clone(), - }) + })) + } + _ => { + error_emitted = Some(handler.emit_err(CompileError::TraitNotFound { + name: supertrait.name.to_string(), + span: supertrait.name.span(), + })) } - _ => errors.push(CompileError::TraitNotFound { - name: supertrait.name.to_string(), - span: supertrait.name.span(), - }), } } - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 083677b8ff0..d57111fe051 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -2,13 +2,13 @@ use std::collections::{BTreeMap, HashSet}; use sway_error::{ error::CompileError, + handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; use sway_types::{style::is_upper_camel_case, Ident, Spanned}; use crate::{ decl_engine::*, - error::*, language::{ parsed::*, ty::{self, TyImplItem, TyTraitItem}, @@ -23,12 +23,10 @@ use crate::{ impl ty::TyTraitDecl { pub(crate) fn type_check( + handler: &Handler, ctx: TypeCheckContext, trait_decl: TraitDeclaration, - ) -> CompileResult { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - + ) -> Result { let TraitDeclaration { name, type_parameters, @@ -41,10 +39,10 @@ impl ty::TyTraitDecl { } = trait_decl; if !is_upper_camel_case(name.as_str()) { - warnings.push(CompileWarning { + handler.emit_warn(CompileWarning { span: name.span(), warning_content: Warning::NonClassCaseTraitName { name: name.clone() }, - }) + }); } let type_engine = ctx.engines.te(); @@ -58,26 +56,18 @@ impl ty::TyTraitDecl { // Type check the type parameters. This will also insert them into the // current namespace. - let new_type_parameters = check!( - TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters), - return err(warnings, errors), - warnings, - errors - ); + let new_type_parameters = + TypeParameter::type_check_type_params(handler, ctx.by_ref(), type_parameters)?; // Recursively make the interface surfaces and methods of the // supertraits available to this trait. - check!( - insert_supertraits_into_namespace( - ctx.by_ref(), - self_type, - &supertraits, - &SupertraitOf::Trait - ), - return err(warnings, errors), - warnings, - errors - ); + insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + self_type, + &supertraits, + &SupertraitOf::Trait, + )?; // type check the interface surface let mut new_interface_surface = vec![]; @@ -88,12 +78,7 @@ impl ty::TyTraitDecl { for item in interface_surface.into_iter() { let decl_name = match item { TraitItem::TraitFn(method) => { - let method = check!( - ty::TyTraitFn::type_check(ctx.by_ref(), method), - return err(warnings, errors), - warnings, - errors - ); + let method = ty::TyTraitFn::type_check(handler, ctx.by_ref(), method)?; let decl_ref = decl_engine.insert(method.clone()); dummy_interface_surface.push(ty::TyImplItem::Fn( decl_engine @@ -104,74 +89,59 @@ impl ty::TyTraitDecl { method.name.clone() } TraitItem::Constant(const_decl) => { - let const_decl = check!( - ty::TyConstantDecl::type_check(ctx.by_ref(), const_decl.clone(),), - return err(warnings, errors), - warnings, - errors - ); + let const_decl = + ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl.clone())?; let decl_ref = ctx.engines.de().insert(const_decl.clone()); new_interface_surface .push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone())); let const_name = const_decl.call_path.suffix.clone(); - check!( - ctx.insert_symbol( - const_name.clone(), - ty::TyDecl::ConstantDecl(ty::ConstantDecl { - name: const_name.clone(), - decl_id: *decl_ref.id(), - decl_span: const_decl.span.clone() - }) - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.insert_symbol( + handler, + const_name.clone(), + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + name: const_name.clone(), + decl_id: *decl_ref.id(), + decl_span: const_decl.span.clone(), + }), + )?; const_name } }; if !ids.insert(decl_name.clone()) { - errors.push(CompileError::MultipleDefinitionsOfName { + handler.emit_err(CompileError::MultipleDefinitionsOfName { name: decl_name.clone(), span: decl_name.span(), - }) + }); } } // insert placeholder functions representing the interface surface // to allow methods to use those functions - check!( - ctx.namespace.insert_trait_implementation( - CallPath { - prefixes: vec![], - suffix: name.clone(), - is_absolute: false, - }, - new_type_parameters.iter().map(|x| x.into()).collect(), - self_type, - &dummy_interface_surface, - &span, - None, - false, - engines, - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace.insert_trait_implementation( + handler, + CallPath { + prefixes: vec![], + suffix: name.clone(), + is_absolute: false, + }, + new_type_parameters.iter().map(|x| x.into()).collect(), + self_type, + &dummy_interface_surface, + &span, + None, + false, + engines, + )?; // Type check the items. let mut new_items = vec![]; for method in methods.into_iter() { - let method = check!( - ty::TyFunctionDecl::type_check(ctx.by_ref(), method.clone(), true, false,), - ty::TyFunctionDecl::error(method), - warnings, - errors - ); + let method = + ty::TyFunctionDecl::type_check(handler, ctx.by_ref(), method.clone(), true, false) + .unwrap_or_else(|_| ty::TyFunctionDecl::error(method)); new_items.push(ty::TyTraitItem::Fn(decl_engine.insert(method))); } @@ -185,7 +155,7 @@ impl ty::TyTraitDecl { attributes, span, }; - ok(typed_trait_decl, warnings, errors) + Ok(typed_trait_decl) } /// Retrieves the interface surface and implemented items for this trait. @@ -327,6 +297,7 @@ impl ty::TyTraitDecl { pub(crate) fn insert_interface_surface_and_items_into_namespace( &self, + handler: &Handler, ctx: TypeCheckContext, trait_name: &CallPath, type_arguments: &[TypeArgument], @@ -376,7 +347,8 @@ impl ty::TyTraitDecl { let const_name = const_decl.call_path.suffix.clone(); all_items.push(TyImplItem::Constant(decl_ref.clone())); let const_shadowing_mode = ctx.const_shadowing_mode(); - ctx.namespace.insert_symbol( + let _ = ctx.namespace.insert_symbol( + handler, const_name.clone(), ty::TyDecl::ConstantDecl(ty::ConstantDecl { name: const_name, @@ -414,7 +386,8 @@ impl ty::TyTraitDecl { // Specifically do not check for conflicting definitions because // this is just a temporary namespace for type checking and // these are not actual impl blocks. - ctx.namespace.insert_trait_implementation( + let _ = ctx.namespace.insert_trait_implementation( + &Handler::default(), trait_name.clone(), type_arguments.to_vec(), type_id, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index 516bbd1a25e..c445151b131 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -2,24 +2,21 @@ use sway_types::{Span, Spanned}; use crate::{ decl_engine::DeclId, - error::*, - language::{ - parsed, - ty::{self}, - Visibility, - }, + language::{parsed, ty, Visibility}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; + +use crate::{ semantic_analysis::{AbiMode, TypeCheckContext}, type_system::*, }; impl ty::TyTraitFn { pub(crate) fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, trait_fn: parsed::TraitFn, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let parsed::TraitFn { name, span, @@ -41,26 +38,28 @@ impl ty::TyTraitFn { // Type check the parameters. let mut typed_parameters = vec![]; for param in parameters.into_iter() { - typed_parameters.push(check!( - ty::TyFunctionParameter::type_check_interface_parameter(ctx.by_ref(), param), - continue, - warnings, - errors - )); + typed_parameters.push( + match ty::TyFunctionParameter::type_check_interface_parameter( + handler, + ctx.by_ref(), + param, + ) { + Ok(res) => res, + Err(_) => continue, + }, + ); } // Type check the return type. - return_type.type_id = check!( - ctx.resolve_type_with_self( + return_type.type_id = ctx + .resolve_type_with_self( + handler, return_type.type_id, &return_type.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); let trait_fn = ty::TyTraitFn { name, @@ -71,7 +70,7 @@ impl ty::TyTraitFn { attributes, }; - ok(trait_fn, warnings, errors) + Ok(trait_fn) } /// This function is used in trait declarations to insert "placeholder" diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index 77c73e5a836..6aa45cfc68f 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -1,24 +1,26 @@ use sway_ast::intrinsics::Intrinsic; -use sway_error::error::{CompileError, Hint}; +use sway_error::{ + error::{CompileError, Hint}, + handler::{ErrorEmitted, Handler}, +}; use sway_types::integer_bits::IntegerBits; use sway_types::Span; use crate::{ engine_threading::*, - error::{err, ok}, language::{parsed::Expression, ty}, semantic_analysis::TypeCheckContext, type_system::*, - CompileResult, }; impl ty::TyIntrinsicFunctionKind { pub(crate) fn type_check( + handler: &Handler, ctx: TypeCheckContext, kind_binding: TypeBinding, arguments: Vec, span: Span, - ) -> CompileResult<(Self, TypeId)> { + ) -> Result<(Self, TypeId), ErrorEmitted> { let TypeBinding { inner: kind, type_arguments, @@ -27,34 +29,36 @@ impl ty::TyIntrinsicFunctionKind { let type_arguments = type_arguments.to_vec(); match kind { Intrinsic::SizeOfVal => { - type_check_size_of_val(ctx, kind, arguments, type_arguments, span) + type_check_size_of_val(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::SizeOfType => { - type_check_size_of_type(ctx, kind, arguments, type_arguments, span) + type_check_size_of_type(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::SizeOfStr => { - type_check_size_of_type(ctx, kind, arguments, type_arguments, span) + type_check_size_of_type(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::IsReferenceType => { - type_check_is_reference_type(ctx, kind, arguments, type_arguments, span) + type_check_is_reference_type(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::IsStrType => { - type_check_is_reference_type(ctx, kind, arguments, type_arguments, span) + type_check_is_reference_type(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::Eq | Intrinsic::Gt | Intrinsic::Lt => { - type_check_cmp(ctx, kind, arguments, span) + type_check_cmp(handler, ctx, kind, arguments, span) + } + Intrinsic::Gtf => type_check_gtf(handler, ctx, kind, arguments, type_arguments, span), + Intrinsic::AddrOf => type_check_addr_of(handler, ctx, kind, arguments, span), + Intrinsic::StateClear => type_check_state_clear(handler, ctx, kind, arguments, span), + Intrinsic::StateLoadWord => { + type_check_state_load_word(handler, ctx, kind, arguments, span) } - Intrinsic::Gtf => type_check_gtf(ctx, kind, arguments, type_arguments, span), - Intrinsic::AddrOf => type_check_addr_of(ctx, kind, arguments, span), - Intrinsic::StateClear => type_check_state_clear(ctx, kind, arguments, span), - Intrinsic::StateLoadWord => type_check_state_load_word(ctx, kind, arguments, span), Intrinsic::StateStoreWord => { - type_check_state_store_word(ctx, kind, arguments, type_arguments, span) + type_check_state_store_word(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::StateLoadQuad | Intrinsic::StateStoreQuad => { - type_check_state_quad(ctx, kind, arguments, type_arguments, span) + type_check_state_quad(handler, ctx, kind, arguments, type_arguments, span) } - Intrinsic::Log => type_check_log(ctx, kind, arguments, span), + Intrinsic::Log => type_check_log(handler, ctx, kind, arguments, span), Intrinsic::Add | Intrinsic::Sub | Intrinsic::Mul @@ -62,16 +66,20 @@ impl ty::TyIntrinsicFunctionKind { | Intrinsic::And | Intrinsic::Or | Intrinsic::Xor - | Intrinsic::Mod => type_check_binary_op(ctx, kind, arguments, type_arguments, span), + | Intrinsic::Mod => { + type_check_binary_op(handler, ctx, kind, arguments, type_arguments, span) + } Intrinsic::Lsh | Intrinsic::Rsh => { - type_check_shift_binary_op(ctx, kind, arguments, type_arguments, span) + type_check_shift_binary_op(handler, ctx, kind, arguments, type_arguments, span) + } + Intrinsic::Revert => { + type_check_revert(handler, ctx, kind, arguments, type_arguments, span) } - Intrinsic::Revert => type_check_revert(ctx, kind, arguments, type_arguments, span), Intrinsic::PtrAdd | Intrinsic::PtrSub => { - type_check_ptr_ops(ctx, kind, arguments, type_arguments, span) + type_check_ptr_ops(handler, ctx, kind, arguments, type_arguments, span) } - Intrinsic::Smo => type_check_smo(ctx, kind, arguments, type_arguments, span), - Intrinsic::Not => type_check_not(ctx, kind, arguments, type_arguments, span), + Intrinsic::Smo => type_check_smo(handler, ctx, kind, arguments, type_arguments, span), + Intrinsic::Not => type_check_not(handler, ctx, kind, arguments, type_arguments, span), } } } @@ -80,25 +88,22 @@ impl ty::TyIntrinsicFunctionKind { /// Description: Return the bitwise negation of the operator. /// Constraints: None. fn type_check_not( + handler: &Handler, ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, _type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let return_type = type_engine.insert(engines, TypeInfo::Numeric); @@ -106,61 +111,44 @@ fn type_check_not( let mut ctx = ctx.with_help_text("").with_type_annotation(return_type); let operand = arguments[0].clone(); - let operand_expr = check!( - ty::TyExpression::type_check(ctx.by_ref(), operand), - return err(warnings, errors), - warnings, - errors - ); + let operand_expr = ty::TyExpression::type_check(handler, ctx.by_ref(), operand)?; - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![operand_expr], - type_arguments: vec![], - span, - }, - return_type, - ), - warnings, - errors, - ) + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![operand_expr], + type_arguments: vec![], + span, + }, + return_type, + )) } /// Signature: `__size_of_val(val: T) -> u64` /// Description: Return the size of type `T` in bytes. /// Constraints: None. fn type_check_size_of_val( + handler: &Handler, ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, _type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let exp = check!( - ty::TyExpression::type_check(ctx, arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); + let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![exp], @@ -169,59 +157,52 @@ fn type_check_size_of_val( }; let return_type = type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__size_of() -> u64` /// Description: Return the size of type `T` in bytes. /// Constraints: None. fn type_check_size_of_type( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if !arguments.is_empty() { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 0, span, - }); - return err(warnings, errors); + })); } if type_arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let targ = type_arguments[0].clone(); - let initial_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let initial_type_info = type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); - let type_id = check!( - ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::Yes, None), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + let type_id = ctx + .resolve_type_with_self( + handler, + initial_type_id, + &targ.span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -235,51 +216,45 @@ fn type_check_size_of_type( }; let return_type = type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__is_reference_type() -> bool` /// Description: Returns `true` if `T` is a _reference type_ and `false` otherwise. /// Constraints: None. fn type_check_is_reference_type( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, _arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if type_arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let targ = type_arguments[0].clone(); - let initial_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let initial_type_info = type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); - let type_id = check!( - ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::Yes, None), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + let type_id = ctx + .resolve_type_with_self( + handler, + initial_type_id, + &targ.span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -291,14 +266,10 @@ fn type_check_is_reference_type( }], span, }; - ok( - ( - intrinsic_function, - type_engine.insert(engines, TypeInfo::Boolean), - ), - warnings, - errors, - ) + Ok(( + intrinsic_function, + type_engine.insert(engines, TypeInfo::Boolean), + )) } /// Signature: `__eq(lhs: T, rhs: T) -> bool` @@ -313,79 +284,56 @@ fn type_check_is_reference_type( /// Description: Returns whether `lhs` < `rhs`. /// Constraints: `T` is `u8`, `u16`, `u32`, `u64`. fn type_check_cmp( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; if arguments.len() != 2 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 2, span, - }); - return err(warnings, errors); + })); } let mut ctx = ctx .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); let lhs = arguments[0].clone(); - let lhs = check!( - ty::TyExpression::type_check(ctx.by_ref(), lhs), - return err(warnings, errors), - warnings, - errors - ); + let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; let rhs = arguments[1].clone(); - let rhs = check!( - ty::TyExpression::type_check(ctx, rhs), - return err(warnings, errors), - warnings, - errors - ); + let rhs = ty::TyExpression::type_check(handler, ctx, rhs)?; // Check for supported argument types - let arg_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(lhs.return_type, &lhs.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let arg_ty = type_engine + .to_typeinfo(lhs.return_type, &lhs.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let is_valid_arg_ty = matches!(arg_ty, TypeInfo::UnsignedInteger(_) | TypeInfo::Numeric) || (matches!(&kind, Intrinsic::Eq) && matches!(arg_ty, TypeInfo::Boolean | TypeInfo::RawUntypedPtr)); if !is_valid_arg_ty { - errors.push(CompileError::IntrinsicUnsupportedArgType { + return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span: lhs.span, hint: Hint::empty(), - }); - return err(warnings, errors); + })); } - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![lhs, rhs], - type_arguments: vec![], - span, - }, - type_engine.insert(engines, TypeInfo::Boolean), - ), - warnings, - errors, - ) + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![lhs, rhs], + type_arguments: vec![], + span, + }, + type_engine.insert(engines, TypeInfo::Boolean), + )) } /// Signature: `__gtf(index: u64, tx_field_id: u64) -> T` @@ -395,146 +343,110 @@ fn type_check_cmp( /// The resuting field is cast to `T`. /// Constraints: None. fn type_check_gtf( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 2 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 2, span, - }); - return err(warnings, errors); + })); } if type_arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } // Type check the first argument which is the index let mut ctx = ctx.by_ref().with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); - let index = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); + let index = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; // Type check the second argument which is the tx field ID let mut ctx = ctx.by_ref().with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); - let tx_field_id = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), - return err(warnings, errors), - warnings, - errors - ); + let tx_field_id = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; let targ = type_arguments[0].clone(); - let initial_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let initial_type_info = type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); - let type_id = check!( - ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::Yes, None), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); - - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![index, tx_field_id], - type_arguments: vec![TypeArgument { - type_id, - initial_type_id, - span: targ.span, - call_path_tree: targ.call_path_tree, - }], - span, - }, - type_id, - ), - warnings, - errors, - ) + let type_id = ctx + .resolve_type_with_self( + handler, + initial_type_id, + &targ.span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![index, tx_field_id], + type_arguments: vec![TypeArgument { + type_id, + initial_type_id, + span: targ.span, + call_path_tree: targ.call_path_tree, + }], + span, + }, + type_id, + )) } /// Signature: `__addr_of(val: T) -> raw_ptr` /// Description: Returns the address in memory where `val` is stored. /// Constraints: `T` is a reference type. fn type_check_addr_of( + handler: &Handler, ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let exp = check!( - ty::TyExpression::type_check(ctx, arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); - let copy_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(exp.return_type, &span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; + let copy_type_info = type_engine + .to_typeinfo(exp.return_type, &span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); if copy_type_info.is_copy_type() { - errors.push(CompileError::IntrinsicUnsupportedArgType { + return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, hint: Hint::new("Only a reference type can be used as argument here".to_string()), - }); - return err(warnings, errors); + })); } let intrinsic_function = ty::TyIntrinsicFunctionKind { @@ -544,7 +456,7 @@ fn type_check_addr_of( span, }; let return_type = type_engine.insert(engines, TypeInfo::RawUntypedPtr); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__state_load_clear(key: b256, slots: u64) -> bool` @@ -552,64 +464,46 @@ fn type_check_addr_of( /// Returns a Boolean describing whether all the storage slots were previously set. /// Constraints: None. fn type_check_state_clear( + handler: &Handler, ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; if arguments.len() != 2 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } // `key` argument let mut ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let key_exp = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); - let key_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(key_exp.return_type, &span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; + let key_ty = type_engine + .to_typeinfo(key_exp.return_type, &span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, ctx.engines()) { - errors.push(CompileError::IntrinsicUnsupportedArgType { + return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, hint: Hint::new("Argument type must be B256, a key into the state storage".to_string()), - }); - return err(warnings, errors); + })); } // `slots` argument let mut ctx = ctx.with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); - let number_of_slots_exp = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), - return err(warnings, errors), - warnings, - errors - ); + let number_of_slots_exp = + ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; // Typed intrinsic let intrinsic_function = ty::TyIntrinsicFunctionKind { @@ -619,57 +513,43 @@ fn type_check_state_clear( span, }; let return_type = type_engine.insert(engines, TypeInfo::Boolean); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__state_load_word(key: b256) -> u64` /// Description: Reads and returns a single word from storage at key `key`. /// Constraints: None. fn type_check_state_load_word( + handler: &Handler, ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; if arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let exp = check!( - ty::TyExpression::type_check(ctx, arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); - let key_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(exp.return_type, &span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; + let key_ty = type_engine + .to_typeinfo(exp.return_type, &span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, engines) { - errors.push(CompileError::IntrinsicUnsupportedArgType { + return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, hint: Hint::new("Argument type must be B256, a key into the state storage".to_string()), - }); - return err(warnings, errors); + })); } let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, @@ -679,7 +559,7 @@ fn type_check_state_load_word( }; let return_type = type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__state_store_word(key: b256, val: u64) -> bool` @@ -687,94 +567,66 @@ fn type_check_state_load_word( /// whether the store slot was previously set. /// Constraints: None. fn type_check_state_store_word( + handler: &Handler, ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; if arguments.len() != 2 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 2, span, - }); - return err(warnings, errors); + })); } if type_arguments.len() > 1 { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let mut ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let key_exp = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); - let key_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(key_exp.return_type, &span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; + let key_ty = type_engine + .to_typeinfo(key_exp.return_type, &span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, ctx.engines()) { - errors.push(CompileError::IntrinsicUnsupportedArgType { + return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, hint: Hint::new("Argument type must be B256, a key into the state storage".to_string()), - }); - return err(warnings, errors); + })); } let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let val_exp = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), - return err(warnings, errors), - warnings, - errors - ); + let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; let ctx = ctx.with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); let type_argument = type_arguments.get(0).map(|targ| { let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let initial_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let initial_type_info = type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); - let type_id = check!( - ctx.resolve_type_with_self( + let type_id = ctx + .resolve_type_with_self( + handler, initial_type_id, &targ.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); TypeArgument { type_id, initial_type_id, @@ -789,7 +641,7 @@ fn type_check_state_store_word( span, }; let return_type = type_engine.insert(engines, TypeInfo::Boolean); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__state_load_quad(key: b256, ptr: raw_ptr, slots: u64)` @@ -804,101 +656,68 @@ fn type_check_state_store_word( /// whether the first storage slot was previously set. /// Constraints: None. fn type_check_state_quad( + handler: &Handler, ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 3 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 3, span, - }); - return err(warnings, errors); + })); } if type_arguments.len() > 1 { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let mut ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let key_exp = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); - let key_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(key_exp.return_type, &span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; + let key_ty = type_engine + .to_typeinfo(key_exp.return_type, &span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, ctx.engines()) { - errors.push(CompileError::IntrinsicUnsupportedArgType { + return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, hint: Hint::new("Argument type must be B256, a key into the state storage".to_string()), - }); - return err(warnings, errors); + })); } let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let val_exp = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), - return err(warnings, errors), - warnings, - errors - ); + let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; let mut ctx = ctx.with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); - let number_of_slots_exp = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[2].clone()), - return err(warnings, errors), - warnings, - errors - ); + let number_of_slots_exp = + ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[2].clone())?; let type_argument = type_arguments.get(0).map(|targ| { let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let initial_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let initial_type_info = type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); - let type_id = check!( - ctx.resolve_type_with_self( + let type_id = ctx + .resolve_type_with_self( + handler, initial_type_id, &targ.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); TypeArgument { type_id, initial_type_id, @@ -913,42 +732,34 @@ fn type_check_state_quad( span, }; let return_type = type_engine.insert(engines, TypeInfo::Boolean); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__log(val: T)` /// Description: Logs value `val`. /// Constraints: None. fn type_check_log( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let ctx = ctx .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let exp = check!( - ty::TyExpression::type_check(ctx, arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); + let exp = ty::TyExpression::type_check(handler, ctx, arguments[0].clone())?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![exp], @@ -956,7 +767,7 @@ fn type_check_log( span, }; let return_type = type_engine.insert(engines, TypeInfo::Tuple(vec![])); - ok((intrinsic_function, return_type), warnings, errors) + Ok((intrinsic_function, return_type)) } /// Signature: `__add(lhs: T, rhs: T) -> T` @@ -987,33 +798,29 @@ fn type_check_log( /// Description: Bitwise Xor `lhs` and `rhs` and returns the result. /// Constraints: `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. fn type_check_binary_op( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 2 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 2, span, - }); - return err(warnings, errors); + })); } if !type_arguments.is_empty() { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 0, span, - }); - return err(warnings, errors); + })); } let return_type = type_engine.insert(engines, TypeInfo::Numeric); @@ -1023,33 +830,19 @@ fn type_check_binary_op( .with_help_text("Incorrect argument type"); let lhs = arguments[0].clone(); - let lhs = check!( - ty::TyExpression::type_check(ctx.by_ref(), lhs), - return err(warnings, errors), - warnings, - errors - ); + let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; let rhs = arguments[1].clone(); - let rhs = check!( - ty::TyExpression::type_check(ctx, rhs), - return err(warnings, errors), - warnings, - errors - ); + let rhs = ty::TyExpression::type_check(handler, ctx, rhs)?; - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![lhs, rhs], - type_arguments: vec![], - span, - }, - return_type, - ), - warnings, - errors, - ) + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![lhs, rhs], + type_arguments: vec![], + span, + }, + return_type, + )) } /// Signature: `__lsh(lhs: T, rhs: U) -> T` @@ -1060,136 +853,107 @@ fn type_check_binary_op( /// Description: Logical right shifts the `lhs` by the `rhs` and returns the result. /// Constraints: `T` and `U` are an integer type, i.e. `u8`, `u16`, `u32`, `u64`. fn type_check_shift_binary_op( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 2 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 2, span, - }); - return err(warnings, errors); + })); } if !type_arguments.is_empty() { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 0, span, - }); - return err(warnings, errors); + })); } let return_type = type_engine.insert(engines, TypeInfo::Numeric); let lhs = arguments[0].clone(); - let lhs = check!( - ty::TyExpression::type_check( - ctx.by_ref() - .with_help_text("Incorrect argument type") - .with_type_annotation(return_type), - lhs - ), - return err(warnings, errors), - warnings, - errors - ); + let lhs = ty::TyExpression::type_check( + handler, + ctx.by_ref() + .with_help_text("Incorrect argument type") + .with_type_annotation(return_type), + lhs, + )?; let rhs = arguments[1].clone(); - let rhs = check!( - ty::TyExpression::type_check( - ctx.by_ref() - .with_help_text("Incorrect argument type") - .with_type_annotation(engines.te().insert(engines, TypeInfo::Numeric)), - rhs - ), - return err(warnings, errors), - warnings, - errors - ); - - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![lhs, rhs], - type_arguments: vec![], - span, - }, - return_type, - ), - warnings, - errors, - ) + let rhs = ty::TyExpression::type_check( + handler, + ctx.by_ref() + .with_help_text("Incorrect argument type") + .with_type_annotation(engines.te().insert(engines, TypeInfo::Numeric)), + rhs, + )?; + + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![lhs, rhs], + type_arguments: vec![], + span, + }, + return_type, + )) } /// Signature: `__revert(code: u64)` /// Description: Reverts with error code `code`. /// Constraints: None. fn type_check_revert( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } if !type_arguments.is_empty() { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 0, span, - }); - return err(warnings, errors); + })); } // Type check the argument which is the revert code let mut ctx = ctx.by_ref().with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); - let revert_code = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); + let revert_code = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![revert_code], - type_arguments: vec![], - span, - }, - type_engine.insert(engines, TypeInfo::Unknown), // TODO: change this to the `Never` type when - // available - ), - warnings, - errors, - ) + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![revert_code], + type_arguments: vec![], + span, + }, + type_engine.insert(engines, TypeInfo::Unknown), // TODO: change this to the `Never` type when + // available + )) } /// Signature: `__ptr_add(ptr: raw_ptr, offset: u64)` @@ -1200,83 +964,64 @@ fn type_check_revert( /// Description: Subtracts `offset` to the raw value of pointer `ptr`. /// Constraints: None. fn type_check_ptr_ops( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 2 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 2, span, - }); - return err(warnings, errors); + })); } if type_arguments.len() != 1 { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } let targ = type_arguments[0].clone(); - let initial_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let initial_type_info = type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); - let type_id = check!( - ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::No, None), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + let type_id = ctx + .resolve_type_with_self( + handler, + initial_type_id, + &targ.span, + EnforceTypeArguments::No, + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); let mut ctx = ctx .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); let lhs = arguments[0].clone(); - let lhs = check!( - ty::TyExpression::type_check(ctx.by_ref(), lhs), - return err(warnings, errors), - warnings, - errors - ); + let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; // Check for supported argument types - let lhs_ty = check!( - CompileResult::from( - type_engine - .to_typeinfo(lhs.return_type, &lhs.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let lhs_ty = type_engine + .to_typeinfo(lhs.return_type, &lhs.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); if !matches!(lhs_ty, TypeInfo::RawUntypedPtr) { - errors.push(CompileError::IntrinsicUnsupportedArgType { + return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span: lhs.span, hint: Hint::empty(), - }); - return err(warnings, errors); + })); } let rhs = arguments[1].clone(); @@ -1286,31 +1031,22 @@ fn type_check_ptr_ops( .with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); - let rhs = check!( - ty::TyExpression::type_check(ctx, rhs), - return err(warnings, errors), - warnings, - errors - ); - - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![lhs, rhs], - type_arguments: vec![TypeArgument { - type_id, - initial_type_id, - span: targ.span, - call_path_tree: targ.call_path_tree, - }], - span, - }, - type_engine.insert(engines, lhs_ty), - ), - warnings, - errors, - ) + let rhs = ty::TyExpression::type_check(handler, ctx, rhs)?; + + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![lhs, rhs], + type_arguments: vec![TypeArgument { + type_id, + initial_type_id, + span: targ.span, + call_path_tree: targ.call_path_tree, + }], + span, + }, + type_engine.insert(engines, lhs_ty), + )) } /// Signature: `__smo(recipient: b256, data: T, coins: u64)` @@ -1318,34 +1054,30 @@ fn type_check_ptr_ops( /// to address `recipient`. /// Constraints: None. fn type_check_smo( + handler: &Handler, mut ctx: TypeCheckContext, kind: sway_ast::Intrinsic, arguments: Vec, type_arguments: Vec, span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut warnings = vec![]; - let mut errors = vec![]; - if arguments.len() != 3 { - errors.push(CompileError::IntrinsicIncorrectNumArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { name: kind.to_string(), expected: 3, span, - }); - return err(warnings, errors); + })); } if type_arguments.len() > 1 { - errors.push(CompileError::IntrinsicIncorrectNumTArgs { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { name: kind.to_string(), expected: 1, span, - }); - return err(warnings, errors); + })); } // Type check the type argument @@ -1354,28 +1086,20 @@ fn type_check_smo( .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let initial_type_info = check!( - CompileResult::from( - type_engine - .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - ), - TypeInfo::ErrorRecovery, - warnings, - errors - ); + let initial_type_info = type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + .unwrap_or_else(|_| TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); - let type_id = check!( - ctx.resolve_type_with_self( + let type_id = ctx + .resolve_type_with_self( + handler, initial_type_id, &targ.span, EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); TypeArgument { type_id, initial_type_id, @@ -1388,12 +1112,7 @@ fn type_check_smo( let mut ctx = ctx .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::B256)); - let recipient = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), - return err(warnings, errors), - warnings, - errors - ); + let recipient = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[0].clone())?; // Type check the second argument which is the data, which can be anything. If a type // argument is provided, make sure that it matches the type of the data. @@ -1404,12 +1123,7 @@ fn type_check_smo( ta.type_id }), ); - let data = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), - return err(warnings, errors), - warnings, - errors - ); + let data = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[1].clone())?; // Type check the third argument which is the output index, so it has to be a `u64`. let mut ctx = ctx.by_ref().with_type_annotation( @@ -1420,24 +1134,15 @@ fn type_check_smo( let mut ctx = ctx.by_ref().with_type_annotation( type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ); - let coins = check!( - ty::TyExpression::type_check(ctx.by_ref(), arguments[2].clone()), - return err(warnings, errors), - warnings, - errors - ); + let coins = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[2].clone())?; - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![recipient, data, coins], - type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), - span, - }, - type_engine.insert(engines, TypeInfo::Tuple(vec![])), - ), - warnings, - errors, - ) + Ok(( + ty::TyIntrinsicFunctionKind { + kind, + arguments: vec![recipient, data, coins], + type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), + span, + }, + type_engine.insert(engines, TypeInfo::Tuple(vec![])), + )) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs index d94df709078..71d6f00d36a 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs @@ -1,11 +1,12 @@ use std::collections::HashSet; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span}; -use crate::{ - decl_engine::DeclEngine, error::*, language::ty, type_system::TypeId, Engines, TypeInfo, -}; +use crate::{decl_engine::DeclEngine, language::ty, type_system::TypeId, Engines, TypeInfo}; use super::{ patstack::PatStack, @@ -62,18 +63,15 @@ impl ConstructorFactory { /// ``` pub(crate) fn create_pattern_not_present( &self, + handler: &Handler, engines: &Engines, sigma: PatStack, span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - let (first, rest) = check!( - sigma.flatten().filter_out_wildcards().split_first(span), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result { + let (first, rest) = sigma + .flatten() + .filter_out_wildcards() + .split_first(handler, span)?; let pat = match first { Pattern::U8(range) => { let mut ranges = vec![range]; @@ -81,30 +79,20 @@ impl ConstructorFactory { match pat { Pattern::U8(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - let unincluded: PatStack = check!( - Range::find_exclusionary_ranges(ranges, Range::u8(), span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(Pattern::U8) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(unincluded, span), - return err(warnings, errors), - warnings, - errors - ) + let unincluded: PatStack = + Range::find_exclusionary_ranges(handler, ranges, Range::u8(), span)? + .into_iter() + .map(Pattern::U8) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, unincluded, span)? } Pattern::U16(range) => { let mut ranges = vec![range]; @@ -112,30 +100,20 @@ impl ConstructorFactory { match pat { Pattern::U16(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - let unincluded: PatStack = check!( - Range::find_exclusionary_ranges(ranges, Range::u16(), span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(Pattern::U16) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(unincluded, span), - return err(warnings, errors), - warnings, - errors - ) + let unincluded: PatStack = + Range::find_exclusionary_ranges(handler, ranges, Range::u16(), span)? + .into_iter() + .map(Pattern::U16) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, unincluded, span)? } Pattern::U32(range) => { let mut ranges = vec![range]; @@ -143,30 +121,20 @@ impl ConstructorFactory { match pat { Pattern::U32(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - let unincluded: PatStack = check!( - Range::find_exclusionary_ranges(ranges, Range::u32(), span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(Pattern::U32) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(unincluded, span), - return err(warnings, errors), - warnings, - errors - ) + let unincluded: PatStack = + Range::find_exclusionary_ranges(handler, ranges, Range::u32(), span)? + .into_iter() + .map(Pattern::U32) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, unincluded, span)? } Pattern::U64(range) => { let mut ranges = vec![range]; @@ -174,30 +142,20 @@ impl ConstructorFactory { match pat { Pattern::U64(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - let unincluded: PatStack = check!( - Range::find_exclusionary_ranges(ranges, Range::u64(), span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(Pattern::U64) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(unincluded, span), - return err(warnings, errors), - warnings, - errors - ) + let unincluded: PatStack = + Range::find_exclusionary_ranges(handler, ranges, Range::u64(), span)? + .into_iter() + .map(Pattern::U64) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, unincluded, span)? } Pattern::Numeric(range) => { let mut ranges = vec![range]; @@ -205,30 +163,20 @@ impl ConstructorFactory { match pat { Pattern::Numeric(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - let unincluded: PatStack = check!( - Range::find_exclusionary_ranges(ranges, Range::u64(), span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(Pattern::Numeric) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(unincluded, span), - return err(warnings, errors), - warnings, - errors - ) + let unincluded: PatStack = + Range::find_exclusionary_ranges(handler, ranges, Range::u64(), span)? + .into_iter() + .map(Pattern::Numeric) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, unincluded, span)? } // we will not present every string case Pattern::String(_) => Pattern::Wildcard, @@ -249,11 +197,10 @@ impl ConstructorFactory { false_found = true; } if true_found && false_found { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "unable to create a new pattern", span.clone(), - )); - return err(warnings, errors); + ))); } else if true_found { Pattern::Boolean(false) } else { @@ -272,73 +219,52 @@ impl ConstructorFactory { )) } ref pat @ Pattern::Enum(ref enum_pattern) => { - let type_info = check!( - self.resolve_possible_types(pat, span, engines.de()), - return err(warnings, errors), - warnings, - errors - ); - let enum_decl = engines.de().get_enum(&check!( - type_info.expect_enum(engines, "", span), - return err(warnings, errors), - warnings, - errors - )); + let type_info = self.resolve_possible_types(handler, pat, span, engines.de())?; + let enum_decl = engines + .de() + .get_enum(&type_info.expect_enum(handler, engines, "", span)?); let enum_name = enum_decl.call_path.suffix; let enum_variants = enum_decl.variants; - let (all_variants, variant_tracker) = check!( - ConstructorFactory::resolve_enum( - &enum_name, - &enum_variants, - enum_pattern, - rest, - span - ), - return err(warnings, errors), - warnings, - errors - ); - check!( - Pattern::from_pat_stack( - PatStack::from( - all_variants - .difference(&variant_tracker) - .map(|x| { - Pattern::Enum(EnumPattern { - enum_name: enum_name.to_string(), - variant_name: x.clone(), - value: Box::new(Pattern::Wildcard), - }) + let (all_variants, variant_tracker) = ConstructorFactory::resolve_enum( + handler, + &enum_name, + &enum_variants, + enum_pattern, + rest, + span, + )?; + Pattern::from_pat_stack( + handler, + PatStack::from( + all_variants + .difference(&variant_tracker) + .map(|x| { + Pattern::Enum(EnumPattern { + enum_name: enum_name.to_string(), + variant_name: x.clone(), + value: Box::new(Pattern::Wildcard), }) - .collect::>() - ), - span + }) + .collect::>(), ), - return err(warnings, errors), - warnings, - errors - ) + span, + )? } Pattern::Tuple(elems) => Pattern::Tuple(PatStack::fill_wildcards(elems.len())), Pattern::Or(elems) => { let mut pat_stack = PatStack::empty(); for pat in elems.into_iter() { - pat_stack.push(check!( - self.create_pattern_not_present(engines, PatStack::from_pattern(pat), span), - return err(warnings, errors), - warnings, - errors - )); + pat_stack.push(self.create_pattern_not_present( + handler, + engines, + PatStack::from_pattern(pat), + span, + )?); } - check!( - Pattern::from_pat_stack(pat_stack, span), - return err(warnings, errors), - warnings, - errors - ) + Pattern::from_pat_stack(handler, pat_stack, span)? } }; - ok(pat, warnings, errors) + Ok(pat) } /// Reports if the `PatStack` Σ is a "complete signature" of the type of the @@ -395,59 +321,48 @@ impl ConstructorFactory { /// from the "`Tuple` with 2 sub-patterns" type. pub(crate) fn is_complete_signature( &self, + handler: &Handler, engines: &Engines, pat_stack: &PatStack, span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { // flatten or patterns - let pat_stack = check!( - pat_stack.clone().serialize_multi_patterns(span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .fold(PatStack::empty(), |mut acc, mut pats| { - acc.append(&mut pats); - acc - }); + let pat_stack = pat_stack + .clone() + .serialize_multi_patterns(handler, span)? + .into_iter() + .fold(PatStack::empty(), |mut acc, mut pats| { + acc.append(&mut pats); + acc + }); if pat_stack.is_empty() { - return ok(false, warnings, errors); + return Ok(false); } if pat_stack.contains(&Pattern::Wildcard) { - return ok(true, warnings, errors); + return Ok(true); } - let (first, mut rest) = check!( - pat_stack.split_first(span), - return err(warnings, errors), - warnings, - errors - ); + let (first, mut rest) = pat_stack.split_first(handler, span)?; match first { // its assumed that no one is ever going to list every string - Pattern::String(_) => ok(false, warnings, errors), + Pattern::String(_) => Ok(false), // its assumed that no one is ever going to list every B256 - Pattern::B256(_) => ok(false, warnings, errors), + Pattern::B256(_) => Ok(false), Pattern::U8(range) => { let mut ranges = vec![range]; for pat in rest.into_iter() { match pat { Pattern::U8(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - Range::do_ranges_equal_range(ranges, Range::u8(), span) + Range::do_ranges_equal_range(handler, ranges, Range::u8(), span) } Pattern::U16(range) => { let mut ranges = vec![range]; @@ -455,15 +370,14 @@ impl ConstructorFactory { match pat { Pattern::U16(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - Range::do_ranges_equal_range(ranges, Range::u16(), span) + Range::do_ranges_equal_range(handler, ranges, Range::u16(), span) } Pattern::U32(range) => { let mut ranges = vec![range]; @@ -471,15 +385,14 @@ impl ConstructorFactory { match pat { Pattern::U32(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - Range::do_ranges_equal_range(ranges, Range::u32(), span) + Range::do_ranges_equal_range(handler, ranges, Range::u32(), span) } Pattern::U64(range) => { let mut ranges = vec![range]; @@ -487,15 +400,14 @@ impl ConstructorFactory { match pat { Pattern::U64(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - Range::do_ranges_equal_range(ranges, Range::u64(), span) + Range::do_ranges_equal_range(handler, ranges, Range::u64(), span) } Pattern::Numeric(range) => { let mut ranges = vec![range]; @@ -503,15 +415,14 @@ impl ConstructorFactory { match pat { Pattern::Numeric(range) => ranges.push(range), _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - Range::do_ranges_equal_range(ranges, Range::u64(), span) + Range::do_ranges_equal_range(handler, ranges, Range::u64(), span) } Pattern::Boolean(b) => { let mut true_found = false; @@ -527,96 +438,66 @@ impl ConstructorFactory { false => false_found = true, }, _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - ok(true_found && false_found, warnings, errors) + Ok(true_found && false_found) } ref pat @ Pattern::Enum(ref enum_pattern) => { - let type_info = check!( - self.resolve_possible_types(pat, span, engines.de()), - return err(warnings, errors), - warnings, - errors - ); - let enum_decl = engines.de().get_enum(&check!( - type_info.expect_enum(engines, "", span), - return err(warnings, errors), - warnings, - errors - )); + let type_info = self.resolve_possible_types(handler, pat, span, engines.de())?; + let enum_decl = engines + .de() + .get_enum(&type_info.expect_enum(handler, engines, "", span)?); let enum_name = enum_decl.call_path.suffix; let enum_variants = enum_decl.variants; - let (all_variants, variant_tracker) = check!( - ConstructorFactory::resolve_enum( - &enum_name, - &enum_variants, - enum_pattern, - rest, - span - ), - return err(warnings, errors), - warnings, - errors - ); - ok( - all_variants.difference(&variant_tracker).next().is_none(), - warnings, - errors, - ) + let (all_variants, variant_tracker) = ConstructorFactory::resolve_enum( + handler, + &enum_name, + &enum_variants, + enum_pattern, + rest, + span, + )?; + Ok(all_variants.difference(&variant_tracker).next().is_none()) } ref tup @ Pattern::Tuple(_) => { for pat in rest.iter() { if !pat.has_the_same_constructor(tup) { - return ok(false, warnings, errors); + return Ok(false); } } - ok(true, warnings, errors) + Ok(true) } ref strct @ Pattern::Struct(_) => { for pat in rest.iter() { if !pat.has_the_same_constructor(strct) { - return ok(false, warnings, errors); + return Ok(false); } } - ok(true, warnings, errors) - } - Pattern::Wildcard => { - errors.push(CompileError::Internal( - "expected the wildcard pattern to be filtered out here", - span.clone(), - )); - err(warnings, errors) + Ok(true) } + Pattern::Wildcard => Err(handler.emit_err(CompileError::Internal( + "expected the wildcard pattern to be filtered out here", + span.clone(), + ))), Pattern::Or(mut elems) => { elems.append(&mut rest); - ok( - check!( - self.is_complete_signature(engines, &elems, span), - return err(warnings, errors), - warnings, - errors - ), - warnings, - errors, - ) + Ok(self.is_complete_signature(handler, engines, &elems, span)?) } } } fn resolve_possible_types( &self, + handler: &Handler, pattern: &Pattern, span: &Span, decl_engine: &DeclEngine, - ) -> CompileResult<&TypeInfo> { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result<&TypeInfo, ErrorEmitted> { let mut type_info = None; for possible_type in self.possible_types.iter() { let matches = pattern.matches_type_info(possible_type, decl_engine); @@ -626,32 +507,27 @@ impl ConstructorFactory { } } match type_info { - Some(type_info) => ok(type_info, warnings, errors), - None => { - errors.push(CompileError::Internal( - "there is no type that matches this pattern", - span.clone(), - )); - err(warnings, errors) - } + Some(type_info) => Ok(type_info), + None => Err(handler.emit_err(CompileError::Internal( + "there is no type that matches this pattern", + span.clone(), + ))), } } fn resolve_enum( + handler: &Handler, enum_name: &Ident, enum_variants: &[ty::TyEnumVariant], enum_pattern: &EnumPattern, rest: PatStack, span: &Span, - ) -> CompileResult<(HashSet, HashSet)> { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result<(HashSet, HashSet), ErrorEmitted> { if enum_pattern.enum_name.as_str() != enum_name.as_str() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected matching enum names", span.clone(), - )); - return err(warnings, errors); + ))); } let mut all_variants: HashSet = HashSet::new(); for variant in enum_variants.iter() { @@ -663,23 +539,21 @@ impl ConstructorFactory { match pat { Pattern::Enum(enum_pattern2) => { if enum_pattern2.enum_name.as_str() != enum_name.as_str() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected matching enum names", span.clone(), - )); - return err(warnings, errors); + ))); } variant_tracker.insert(enum_pattern2.variant_name.to_string()); } _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "expected all patterns to be of the same type", span.clone(), - )); - return err(warnings, errors); + ))); } } } - ok((all_variants, variant_tracker), warnings, errors) + Ok((all_variants, variant_tracker)) } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/matrix.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/matrix.rs index f048313846c..757cb16ec1a 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/matrix.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/matrix.rs @@ -1,9 +1,7 @@ +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; -use crate::{ - error::{err, ok}, - CompileError, CompileResult, -}; +use crate::CompileError; use super::patstack::PatStack; @@ -54,41 +52,39 @@ impl Matrix { /// Returns the number of rows *m* and the number of columns *n* of the /// `Matrix` in the form (*m*, *n*). - pub(crate) fn m_n(&self, span: &Span) -> CompileResult<(usize, usize)> { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn m_n( + &self, + handler: &Handler, + span: &Span, + ) -> Result<(usize, usize), ErrorEmitted> { let first = match self.rows.first() { Some(first) => first, - None => return ok((0, 0), warnings, errors), + None => return Ok((0, 0)), }; let n = first.len(); for row in self.rows.iter().skip(1) { if row.len() != n { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "found invalid matrix size", span.clone(), - )); - return err(warnings, errors); + ))); } } - ok((self.rows.len(), n), warnings, errors) + Ok((self.rows.len(), n)) } /// Computes Σ, where Σ is a `PatStack` containing the first element of /// every row of the `Matrix`. - pub(crate) fn compute_sigma(&self, span: &Span) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn compute_sigma( + &self, + handler: &Handler, + span: &Span, + ) -> Result { let mut pat_stack = PatStack::empty(); for row in self.rows.iter() { - let first = check!( - row.first(span), - return err(warnings, errors), - warnings, - errors - ); + let first = row.first(handler, span)?; pat_stack.push(first.into_root_constructor()) } - ok(pat_stack.remove_duplicates(), warnings, errors) + Ok(pat_stack.remove_duplicates()) } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/patstack.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/patstack.rs index 04f144c41f5..3fc82e30e09 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/patstack.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/patstack.rs @@ -1,12 +1,10 @@ use std::{cmp::Ordering, fmt, slice::Iter, vec::IntoIter}; use itertools::Itertools; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; -use crate::{ - error::{err, ok}, - CompileError, CompileResult, -}; +use crate::CompileError; use super::pattern::Pattern; @@ -39,52 +37,48 @@ impl PatStack { } /// Returns the first element of a `PatStack`. - pub(crate) fn first(&self, span: &Span) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn first(&self, handler: &Handler, span: &Span) -> Result { match self.pats.first() { - Some(first) => ok(first.to_owned(), warnings, errors), - None => { - errors.push(CompileError::Internal("empty PatStack", span.clone())); - err(warnings, errors) - } + Some(first) => Ok(first.to_owned()), + None => Err(handler.emit_err(CompileError::Internal("empty PatStack", span.clone()))), } } /// Returns a tuple of the first element of a `PatStack` and the rest of the /// elements. - pub(crate) fn split_first(&self, span: &Span) -> CompileResult<(Pattern, PatStack)> { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn split_first( + &self, + handler: &Handler, + span: &Span, + ) -> Result<(Pattern, PatStack), ErrorEmitted> { match self.pats.split_first() { Some((first, pat_stack_contents)) => { let pat_stack = PatStack { pats: pat_stack_contents.to_vec(), }; - ok((first.to_owned(), pat_stack), warnings, errors) - } - None => { - errors.push(CompileError::Internal("empty PatStack", span.clone())); - err(warnings, errors) + Ok((first.to_owned(), pat_stack)) } + None => Err(handler.emit_err(CompileError::Internal("empty PatStack", span.clone()))), } } /// Given a usize *n*, splits the `PatStack` at *n* and returns both halves. - pub(crate) fn split_at(&self, n: usize, span: &Span) -> CompileResult<(PatStack, PatStack)> { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn split_at( + &self, + handler: &Handler, + n: usize, + span: &Span, + ) -> Result<(PatStack, PatStack), ErrorEmitted> { if n > self.len() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "attempting to split OOB", span.clone(), - )); - return err(warnings, errors); + ))); } let (a, b) = self.pats.split_at(n); let x = PatStack { pats: a.to_vec() }; let y = PatStack { pats: b.to_vec() }; - ok((x, y), warnings, errors) + Ok((x, y)) } /// Pushes a `Pattern` onto the `PatStack` @@ -94,18 +88,18 @@ impl PatStack { /// Given a usize *n*, returns a mutable reference to the `PatStack` at /// index *n*. - fn get_mut(&mut self, n: usize, span: &Span) -> CompileResult<&mut Pattern> { - let warnings = vec![]; - let mut errors = vec![]; + fn get_mut( + &mut self, + handler: &Handler, + n: usize, + span: &Span, + ) -> Result<&mut Pattern, ErrorEmitted> { match self.pats.get_mut(n) { - Some(elem) => ok(elem, warnings, errors), - None => { - errors.push(CompileError::Internal( - "cant retrieve mutable reference to element", - span.clone(), - )); - err(warnings, errors) - } + Some(elem) => Ok(elem), + None => Err(handler.emit_err(CompileError::Internal( + "cant retrieve mutable reference to element", + span.clone(), + ))), } } @@ -260,17 +254,20 @@ impl PatStack { /// ], /// ] /// ``` - pub(crate) fn serialize_multi_patterns(self, span: &Span) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn serialize_multi_patterns( + self, + handler: &Handler, + span: &Span, + ) -> Result, ErrorEmitted> { let mut output: Vec = vec![]; let mut stack: Vec = vec![self]; while !stack.is_empty() { let top = match stack.pop() { Some(top) => top, None => { - errors.push(CompileError::Internal("can't pop Vec", span.clone())); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::Internal("can't pop Vec", span.clone())) + ); } }; if !top.contains_or_pattern() { @@ -280,12 +277,7 @@ impl PatStack { if let Pattern::Or(elems) = pat { for elem in elems.into_iter() { let mut top = top.clone(); - let r = check!( - top.get_mut(i, span), - return err(warnings, errors), - warnings, - errors - ); + let r = top.get_mut(handler, i, span)?; let _ = std::mem::replace(r, elem); stack.push(top); } @@ -294,7 +286,7 @@ impl PatStack { } } output.reverse(); - ok(output, warnings, errors) + Ok(output) } /// Orders a `PatStack` into a human-readable order. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs index f36ce58c6dd..36447d31b2c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs @@ -2,10 +2,11 @@ use std::{cmp::Ordering, fmt}; use std::fmt::Write; use sway_error::error::CompileError; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; use crate::decl_engine::DeclEngine; -use crate::{error::*, language::ty, language::Literal, TypeInfo}; +use crate::{language::ty, language::Literal, TypeInfo}; use super::{patstack::PatStack, range::Range}; @@ -113,9 +114,7 @@ pub(crate) enum Pattern { impl Pattern { /// Converts a `Scrutinee` to a `Pattern`. - pub(crate) fn from_scrutinee(scrutinee: ty::TyScrutinee) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn from_scrutinee(scrutinee: ty::TyScrutinee) -> Self { let pat = match scrutinee.variant { ty::TyScrutineeVariant::CatchAll => Pattern::Wildcard, ty::TyScrutineeVariant::Variable(_) => Pattern::Wildcard, @@ -129,12 +128,7 @@ impl Pattern { let mut new_fields = vec![]; for field in fields.into_iter() { let f = match field.scrutinee { - Some(scrutinee) => check!( - Pattern::from_scrutinee(scrutinee), - return err(warnings, errors), - warnings, - errors - ), + Some(scrutinee) => Pattern::from_scrutinee(scrutinee), None => Pattern::Wildcard, }; new_fields.push((field.field.as_str().to_string(), f)); @@ -147,24 +141,14 @@ impl Pattern { ty::TyScrutineeVariant::Or(elems) => { let mut new_elems = PatStack::empty(); for elem in elems.into_iter() { - new_elems.push(check!( - Pattern::from_scrutinee(elem), - return err(warnings, errors), - warnings, - errors - )); + new_elems.push(Pattern::from_scrutinee(elem)); } Pattern::Or(new_elems) } ty::TyScrutineeVariant::Tuple(elems) => { let mut new_elems = PatStack::empty(); for elem in elems.into_iter() { - new_elems.push(check!( - Pattern::from_scrutinee(elem), - return err(warnings, errors), - warnings, - errors - )); + new_elems.push(Pattern::from_scrutinee(elem)); } Pattern::Tuple(new_elems) } @@ -176,15 +160,10 @@ impl Pattern { } => Pattern::Enum(EnumPattern { enum_name: enum_ref.name().to_string(), variant_name: variant.name.to_string(), - value: Box::new(check!( - Pattern::from_scrutinee(*value), - return err(warnings, errors), - warnings, - errors - )), + value: Box::new(Pattern::from_scrutinee(*value)), }), }; - ok(pat, warnings, errors) + pat } /// Convert the given literal `value` into a pattern. @@ -204,11 +183,15 @@ impl Pattern { /// Converts a `PatStack` to a `Pattern`. If the `PatStack` is of length 1, /// this function returns the single element, if it is of length > 1, this /// function wraps the provided `PatStack` in a `Pattern::Or(..)`. - pub(crate) fn from_pat_stack(pat_stack: PatStack, span: &Span) -> CompileResult { + pub(crate) fn from_pat_stack( + handler: &Handler, + pat_stack: PatStack, + span: &Span, + ) -> Result { if pat_stack.len() == 1 { - pat_stack.first(span) + pat_stack.first(handler, span) } else { - ok(Pattern::Or(pat_stack), vec![], vec![]) + Ok(Pattern::Or(pat_stack)) } } @@ -315,225 +298,170 @@ impl Pattern { /// ]) /// ``` pub(crate) fn from_constructor_and_arguments( + handler: &Handler, c: &Pattern, args: PatStack, span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result { let pat = match c { Pattern::Wildcard => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::Wildcard } Pattern::U8(range) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::U8(range.clone()) } Pattern::U16(range) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::U16(range.clone()) } Pattern::U32(range) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::U32(range.clone()) } Pattern::U64(range) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::U64(range.clone()) } Pattern::B256(b) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::B256(*b) } Pattern::Boolean(b) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::Boolean(*b) } Pattern::Numeric(range) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::Numeric(range.clone()) } Pattern::String(s) => { if !args.is_empty() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } Pattern::String(s.clone()) } Pattern::Struct(struct_pattern) => { if args.len() != struct_pattern.fields.len() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } - let pats: PatStack = check!( - args.serialize_multi_patterns(span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(|args| { - Pattern::Struct(StructPattern { - struct_name: struct_pattern.struct_name.clone(), - fields: struct_pattern - .fields - .iter() - .zip(args.into_iter()) - .map(|((name, _), arg)| (name.clone(), arg)) - .collect::>(), + let pats: PatStack = args + .serialize_multi_patterns(handler, span)? + .into_iter() + .map(|args| { + Pattern::Struct(StructPattern { + struct_name: struct_pattern.struct_name.clone(), + fields: struct_pattern + .fields + .iter() + .zip(args.into_iter()) + .map(|((name, _), arg)| (name.clone(), arg)) + .collect::>(), + }) }) - }) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(pats, span), - return err(warnings, errors), - warnings, - errors - ) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, pats, span)? } Pattern::Enum(enum_pattern) => { if args.len() != 1 { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } - let serialized_args = check!( - args.serialize_multi_patterns(span), - return err(warnings, errors), - warnings, - errors - ); + let serialized_args = args.serialize_multi_patterns(handler, span)?; let mut pats: PatStack = PatStack::empty(); for args in serialized_args.into_iter() { - let arg = check!( - args.first(span), - return err(warnings, errors), - warnings, - errors - ); + let arg = args.first(handler, span)?; pats.push(Pattern::Enum(EnumPattern { enum_name: enum_pattern.enum_name.clone(), variant_name: enum_pattern.variant_name.clone(), value: Box::new(arg), })); } - check!( - Pattern::from_pat_stack(pats, span), - return err(warnings, errors), - warnings, - errors - ) + + Pattern::from_pat_stack(handler, pats, span)? } Pattern::Tuple(elems) => { if elems.len() != args.len() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } - let pats: PatStack = check!( - args.serialize_multi_patterns(span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(Pattern::Tuple) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(pats, span), - return err(warnings, errors), - warnings, - errors - ) + let pats: PatStack = args + .serialize_multi_patterns(handler, span)? + .into_iter() + .map(Pattern::Tuple) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, pats, span)? } Pattern::Or(elems) => { if elems.len() != args.len() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "malformed constructor request", span.clone(), - )); - return err(warnings, errors); + ))); } - let pats: PatStack = check!( - args.serialize_multi_patterns(span), - return err(warnings, errors), - warnings, - errors - ) - .into_iter() - .map(Pattern::Or) - .collect::>() - .into(); - check!( - Pattern::from_pat_stack(pats, span), - return err(warnings, errors), - warnings, - errors - ) + let pats: PatStack = args + .serialize_multi_patterns(handler, span)? + .into_iter() + .map(Pattern::Or) + .collect::>() + .into(); + Pattern::from_pat_stack(handler, pats, span)? } }; - ok(pat, warnings, errors) + Ok(pat) } /// Create a `Pattern::Wildcard` @@ -654,9 +582,11 @@ impl Pattern { /// Pattern::U64(Range { first: 1, last: 1 }) /// ] /// ``` - pub(crate) fn sub_patterns(&self, span: &Span) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn sub_patterns( + &self, + handler: &Handler, + span: &Span, + ) -> Result { let pats = match self { Pattern::Struct(StructPattern { fields, .. }) => fields .iter() @@ -668,13 +598,12 @@ impl Pattern { _ => PatStack::empty(), }; if self.a() != pats.len() { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "invariant self.a() == pats.len() broken", span.clone(), - )); - return err(warnings, errors); + ))); } - ok(pats, warnings, errors) + Ok(pats) } /// Performs a one-layer-deep flattening of a `Pattern` into a `PatStack`. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/range.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/range.rs index 40b985b1f0c..5f18fa820b6 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/range.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/range.rs @@ -4,11 +4,9 @@ use std::{ ops::Sub, }; -use crate::{ - error::{err, ok}, - CompileError, CompileResult, -}; +use crate::CompileError; use itertools::Itertools; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; pub(crate) trait MyMath { @@ -178,17 +176,19 @@ where /// Creates a `Range` and ensures that it is a "valid `Range`" /// (i.e.) that `first` is <= to `last` - fn from_double(first: T, last: T, span: &Span) -> CompileResult> { - let warnings = vec![]; - let mut errors = vec![]; + fn from_double( + handler: &Handler, + first: T, + last: T, + span: &Span, + ) -> Result, ErrorEmitted> { if last < first { - errors.push(CompileError::Internal( + Err(handler.emit_err(CompileError::Internal( "attempted to create an invalid range", span.clone(), - )); - err(warnings, errors) + ))) } else { - ok(Range { first, last }, warnings, errors) + Ok(Range { first, last }) } } @@ -246,15 +246,17 @@ where /// last: 7 /// } /// ``` - fn join_ranges(a: &Range, b: &Range, span: &Span) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + fn join_ranges( + handler: &Handler, + a: &Range, + b: &Range, + span: &Span, + ) -> Result, ErrorEmitted> { if !a.overlaps(b) && !a.within_one(b) { - errors.push(CompileError::Internal( + Err(handler.emit_err(CompileError::Internal( "these two ranges cannot be joined", span.clone(), - )); - err(warnings, errors) + ))) } else { let first = if a.first < b.first { a.first.clone() @@ -266,13 +268,8 @@ where } else { b.last.clone() }; - let range = check!( - Range::from_double(first, last, span), - return err(warnings, errors), - warnings, - errors - ); - ok(range, warnings, errors) + let range = Range::from_double(handler, first, last, span)?; + Ok(range) } } @@ -290,9 +287,11 @@ where /// and ending time of current interval is more than that of stack top, /// update stack top with the ending time of current interval. /// 4. At the end stack contains the merged intervals. - fn condense_ranges(ranges: Vec>, span: &Span) -> CompileResult>> { - let mut warnings = vec![]; - let mut errors = vec![]; + fn condense_ranges( + handler: &Handler, + ranges: Vec>, + span: &Span, + ) -> Result>, ErrorEmitted> { let mut ranges = ranges; let mut stack: Vec> = vec![]; @@ -303,8 +302,9 @@ where let (first, rest) = match ranges.split_first() { Some((first, rest)) => (first.to_owned(), rest.to_owned()), None => { - errors.push(CompileError::Internal("unable to split vec", span.clone())); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::Internal("unable to split vec", span.clone())) + ); } }; stack.push(first); @@ -313,20 +313,16 @@ where let top = match stack.pop() { Some(top) => top, None => { - errors.push(CompileError::Internal("stack empty", span.clone())); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::Internal("stack empty", span.clone())) + ); } }; if range.overlaps(&top) || range.within_one(&top) { // 3b. If the current interval overlaps with stack top (or is within ± 1) // and ending time of current interval is more than that of stack top, // update stack top with the ending time of current interval. - stack.push(check!( - Range::join_ranges(range, &top, span), - return err(warnings, errors), - warnings, - errors - )); + stack.push(Range::join_ranges(handler, range, &top, span)?); } else { // 3a. If the current interval does not overlap with the stack // top, push it. @@ -335,7 +331,7 @@ where } } stack.reverse(); - ok(stack, warnings, errors) + Ok(stack) } /// Given an *oracle* `Range` and a vec *guides* of `Range`, this @@ -369,30 +365,22 @@ where /// 6. Combine the range given from step (3), the ranges given from step /// (4), and the range given from step (5) for your result. pub(crate) fn find_exclusionary_ranges( + handler: &Handler, guides: Vec>, oracle: Range, span: &Span, - ) -> CompileResult>> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result>, ErrorEmitted> { // 1. Convert *guides* to a vec of ordered, distinct, non-overlapping // ranges *guides*' - let condensed = check!( - Range::condense_ranges(guides, span), - return err(warnings, errors), - warnings, - errors - ); + let condensed = Range::condense_ranges(handler, guides, span)?; // 2. Check to ensure that *oracle* fully encompasses all ranges in // *guides*'. if !oracle.encompasses_all(&condensed) { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "ranges OOB with the oracle", span.clone(), - )); - return err(warnings, errors); + ))); } // 3. Given the *oracle* range `[a, b]` and the *guides*'₀ range of @@ -401,17 +389,18 @@ where let (first, last) = match (condensed.split_first(), condensed.split_last()) { (Some((first, _)), Some((last, _))) => (first, last), _ => { - errors.push(CompileError::Internal("could not split vec", span.clone())); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::Internal("could not split vec", span.clone())) + ); } }; if oracle.first != first.first { - exclusionary.push(check!( - Range::from_double(oracle.first.clone(), first.first.decr(), span), - return err(warnings, errors), - warnings, - errors - )); + exclusionary.push(Range::from_double( + handler, + oracle.first.clone(), + first.first.decr(), + span, + )?); } // 4. Given *guides*' of length *n*, for every *k* 0..*n-1*, find the @@ -419,57 +408,50 @@ where // construct a range of `[b, c]`. You can assume that `b != d` because // of step (1) for (left, right) in condensed.iter().tuple_windows() { - exclusionary.push(check!( - Range::from_double(left.last.incr(), right.first.decr(), span), - return err(warnings, errors), - warnings, - errors - )); + exclusionary.push(Range::from_double( + handler, + left.last.incr(), + right.first.decr(), + span, + )?); } // 5. Given the *oracle* range of `[a, b]`, *guides*' of length *n*, and // the *guides*'ₙ range of `[c, d]`, and `b != d`, construct a range of // `[b, d]`. if oracle.last != last.last { - exclusionary.push(check!( - Range::from_double(last.last.incr(), oracle.last, span), - return err(warnings, errors), - warnings, - errors - )); + exclusionary.push(Range::from_double( + handler, + last.last.incr(), + oracle.last, + span, + )?); } // 6. Combine the range given from step (3), the ranges given from step // (4), and the range given from step (5) for your result. - ok(exclusionary, warnings, errors) + Ok(exclusionary) } /// Condenses a vec of ranges and checks to see if the condensed ranges /// equal an oracle range. pub(crate) fn do_ranges_equal_range( + handler: &Handler, ranges: Vec>, oracle: Range, span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - let condensed_ranges = check!( - Range::condense_ranges(ranges, span), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result { + let condensed_ranges = Range::condense_ranges(handler, ranges, span)?; if condensed_ranges.len() > 1 { - ok(false, warnings, errors) + Ok(false) } else { let first_range = match condensed_ranges.first() { Some(first_range) => first_range.clone(), _ => { - errors.push(CompileError::Internal("vec empty", span.clone())); - return err(warnings, errors); + return Err(handler.emit_err(CompileError::Internal("vec empty", span.clone()))); } }; - ok(first_range == oracle, warnings, errors) + Ok(first_range == oracle) } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs index 33b64e47426..0f240e6d15c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs @@ -1,12 +1,10 @@ -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::Span; -use crate::{ - error::{err, ok}, - language::ty, - type_system::TypeId, - CompileResult, Engines, -}; +use crate::{language::ty, type_system::TypeId, Engines}; use super::{ constructor_factory::ConstructorFactory, matrix::Matrix, patstack::PatStack, pattern::Pattern, @@ -198,13 +196,12 @@ use super::{ /// exhaustive if the imaginary additional wildcard pattern has an empty /// `WitnessReport`. pub(crate) fn check_match_expression_usefulness( + handler: &Handler, engines: &Engines, type_id: TypeId, scrutinees: Vec, span: Span, -) -> CompileResult<(WitnessReport, Vec)> { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result<(WitnessReport, Vec), ErrorEmitted> { let mut matrix = Matrix::empty(); let mut arms_reachability = vec![]; @@ -220,24 +217,14 @@ pub(crate) fn check_match_expression_usefulness( { let witness_report = WitnessReport::NoWitnesses; let arms_reachability = vec![]; - return ok((witness_report, arms_reachability), warnings, errors); + return Ok((witness_report, arms_reachability)); } let factory = ConstructorFactory::new(engines, type_id); for scrutinee in scrutinees.into_iter() { - let pat = check!( - Pattern::from_scrutinee(scrutinee.clone()), - return err(warnings, errors), - warnings, - errors - ); + let pat = Pattern::from_scrutinee(scrutinee.clone()); let v = PatStack::from_pattern(pat); - let witness_report = check!( - is_useful(engines, &factory, &matrix, &v, &span), - return err(warnings, errors), - warnings, - errors - ); + let witness_report = is_useful(handler, engines, &factory, &matrix, &v, &span)?; matrix.push(v); // if an arm has witnesses to its usefulness then it is reachable arms_reachability.push(ReachableReport::new( @@ -246,14 +233,9 @@ pub(crate) fn check_match_expression_usefulness( )); } let v = PatStack::from_pattern(Pattern::wild_pattern()); - let witness_report = check!( - is_useful(engines, &factory, &matrix, &v, &span), - return err(warnings, errors), - warnings, - errors - ); + let witness_report = is_useful(handler, engines, &factory, &matrix, &v, &span)?; // if a wildcard case has no witnesses to its usefulness, then the match arms are exhaustive - ok((witness_report, arms_reachability), warnings, errors) + Ok((witness_report, arms_reachability)) } /// Given a `Matrix` *P* and a `PatStack` *q*, computes a `WitnessReport` from @@ -270,51 +252,25 @@ pub(crate) fn check_match_expression_usefulness( /// pattern, or-pattern, or constructed pattern we do something different. Each /// case returns a witness report that we propagate through the recursive steps. fn is_useful( + handler: &Handler, engines: &Engines, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, span: &Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - - let (m, n) = check!(p.m_n(span), return err(warnings, errors), warnings, errors); +) -> Result { + let (m, n) = p.m_n(handler, span)?; match (m, n) { - (0, 0) => ok( - WitnessReport::Witnesses(PatStack::fill_wildcards(q.len())), - warnings, - errors, - ), - (_, 0) => ok(WitnessReport::NoWitnesses, warnings, errors), + (0, 0) => Ok(WitnessReport::Witnesses(PatStack::fill_wildcards(q.len()))), + (_, 0) => Ok(WitnessReport::NoWitnesses), (_, _) => { - let c = check!( - q.first(span), - return err(warnings, errors), - warnings, - errors - ); + let c = q.first(handler, span)?; let witness_report = match c { - Pattern::Wildcard => check!( - is_useful_wildcard(engines, factory, p, q, span), - return err(warnings, errors), - warnings, - errors - ), - Pattern::Or(pats) => check!( - is_useful_or(engines, factory, p, q, pats, span), - return err(warnings, errors), - warnings, - errors - ), - c => check!( - is_useful_constructed(engines, factory, p, q, c, span), - return err(warnings, errors), - warnings, - errors - ), + Pattern::Wildcard => is_useful_wildcard(handler, engines, factory, p, q, span)?, + Pattern::Or(pats) => is_useful_or(handler, engines, factory, p, q, pats, span)?, + c => is_useful_constructed(handler, engines, factory, p, q, c, span)?, }; - ok(witness_report, warnings, errors) + Ok(witness_report) } } } @@ -357,31 +313,19 @@ fn is_useful( /// 5. Add this new pattern to the resulting witness report /// 6. Return the witness report fn is_useful_wildcard( + handler: &Handler, engines: &Engines, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, span: &Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { // 1. Compute Σ = {c₁, ... , cₙ}, which is the set of constructors that appear // as root constructors of the patterns of *P*'s first column. - let sigma = check!( - p.compute_sigma(span), - return err(warnings, errors), - warnings, - errors - ); + let sigma = p.compute_sigma(handler, span)?; // 2. Determine if Σ is a complete signature. - let is_complete_signature = check!( - factory.is_complete_signature(engines, &sigma, span), - return err(warnings, errors), - warnings, - errors - ); + let is_complete_signature = factory.is_complete_signature(handler, engines, &sigma, span)?; if is_complete_signature { // 3. If it is a complete signature: @@ -391,20 +335,16 @@ fn is_useful_wildcard( for c_k in sigma.iter() { // 3.1. For every every *k* 0..*n*, compute the specialized `Matrix` // *S(cₖ, P)* - let s_c_k_p = check!( - compute_specialized_matrix(c_k, p, q, span), - return err(warnings, errors), - warnings, - errors - ); + let s_c_k_p = compute_specialized_matrix(handler, c_k, p, q, span)?; // 3.2. Compute the specialized `Matrix` *S(cₖ, q)* - let s_c_k_q = check!( - compute_specialized_matrix(c_k, &Matrix::from_pat_stack(q.clone()), q, span), - return err(warnings, errors), - warnings, - errors - ); + let s_c_k_q = compute_specialized_matrix( + handler, + c_k, + &Matrix::from_pat_stack(q.clone()), + q, + span, + )?; // *S(cₖ, q)* may have multiple rows in the case of a or pattern // in that case we define: *U(P,((r1∣r2) q2...qn)) = U(P,(r1 q2...qn)) ∨ U(P,(r2 q2...qn))* @@ -413,12 +353,7 @@ fn is_useful_wildcard( for s_c_k_q in s_c_k_q.rows() { // 3.3. Recursively compute U(S(cₖ, P), S(cₖ, q)) - let new_wr = check!( - is_useful(engines, factory, &s_c_k_p, s_c_k_q, span), - return err(warnings, errors), - warnings, - errors - ); + let new_wr = is_useful(handler, engines, factory, &s_c_k_p, s_c_k_q, span)?; wr = WitnessReport::join_witness_reports(wr, new_wr); } @@ -432,24 +367,16 @@ fn is_useful_wildcard( (WitnessReport::NoWitnesses, WitnessReport::NoWitnesses) => {} (WitnessReport::Witnesses(_), WitnessReport::NoWitnesses) => {} (WitnessReport::NoWitnesses, wr @ WitnessReport::Witnesses(_)) => { - let (pat, wr) = check!( - WitnessReport::split_into_leading_constructor(wr, c_k, span), - return err(warnings, errors), - warnings, - errors - ); + let (pat, wr) = + WitnessReport::split_into_leading_constructor(handler, wr, c_k, span)?; if !pat_stack.contains(&pat) { pat_stack.push(pat); } witness_report = wr; } (_, wr) => { - let (pat, wr) = check!( - WitnessReport::split_into_leading_constructor(wr, c_k, span), - return err(warnings, errors), - warnings, - errors - ); + let (pat, wr) = + WitnessReport::split_into_leading_constructor(handler, wr, c_k, span)?; if !pat_stack.contains(&pat) { pat_stack.push(pat); } @@ -463,75 +390,40 @@ fn is_useful_wildcard( match &mut witness_report { WitnessReport::NoWitnesses => {} witness_report => { - let pat_stack = check!( - Pattern::from_pat_stack(pat_stack, span), - return err(warnings, errors), - warnings, - errors - ); - check!( - witness_report.add_witness(pat_stack, span), - return err(warnings, errors), - warnings, - errors - ); + let pat_stack = Pattern::from_pat_stack(handler, pat_stack, span)?; + witness_report.add_witness(handler, pat_stack, span)? } } // 7. Return the witness report - ok(witness_report, warnings, errors) + Ok(witness_report) } else { // 4. If it is not a complete signature: // 4.1. Compute the default `Matrix` *D(P)* - let d_p = check!( - compute_default_matrix(p, q, span), - return err(warnings, errors), - warnings, - errors - ); + let d_p = compute_default_matrix(handler, p, q, span)?; // 4.2. Compute *q'* as \[q₂ ... qₙ*\]. - let (_, q_rest) = check!( - q.split_first(span), - return err(warnings, errors), - warnings, - errors - ); + let (_, q_rest) = q.split_first(handler, span)?; // 4.3. Recursively compute *U(D(P), q')*. - let mut witness_report = check!( - is_useful(engines, factory, &d_p, &q_rest, span), - return err(warnings, errors), - warnings, - errors - ); + let mut witness_report = is_useful(handler, engines, factory, &d_p, &q_rest, span)?; // 4.4. If Σ is empty, create a pattern not present in Σ let witness_to_add = if sigma.is_empty() { Pattern::Wildcard } else { - check!( - factory.create_pattern_not_present(engines, sigma, span), - return err(warnings, errors), - warnings, - errors - ) + factory.create_pattern_not_present(handler, engines, sigma, span)? }; // 4.5. Add this new pattern to the resulting witness report match &mut witness_report { WitnessReport::NoWitnesses => {} - witness_report => check!( - witness_report.add_witness(witness_to_add, span), - return err(warnings, errors), - warnings, - errors - ), + witness_report => witness_report.add_witness(handler, witness_to_add, span)?, } // 4.6. Return the witness report - ok(witness_report, warnings, errors) + Ok(witness_report) } } @@ -548,47 +440,31 @@ fn is_useful_wildcard( /// 2. Extract the specialized `Matrix` *S(c, q)* /// 3. Recursively compute *U(S(c, P), S(c, q))* fn is_useful_constructed( + handler: &Handler, engines: &Engines, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, c: Pattern, span: &Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { // 1. Extract the specialized `Matrix` *S(c, P)* - let s_c_p = check!( - compute_specialized_matrix(&c, p, q, span), - return err(warnings, errors), - warnings, - errors - ); + let s_c_p = compute_specialized_matrix(handler, &c, p, q, span)?; // 2. Extract the specialized `Matrix` *S(c, q)* - let s_c_q = check!( - compute_specialized_matrix(&c, &Matrix::from_pat_stack(q.clone()), q, span), - return err(warnings, errors), - warnings, - errors - ); + let s_c_q = + compute_specialized_matrix(handler, &c, &Matrix::from_pat_stack(q.clone()), q, span)?; // *S(c, q)* may have multiple rows in the case of a or pattern // in that case we define: *U(P,((r1∣r2) q2...qn)) = U(P,(r1 q2...qn)) ∨ U(P,(r2 q2...qn))* let mut witness_report = WitnessReport::NoWitnesses; for s_c_q in s_c_q.rows() { // 3. Recursively compute *U(S(c, P), S(c, q))* - let wr = check!( - is_useful(engines, factory, &s_c_p, s_c_q, span), - return err(warnings, errors), - warnings, - errors - ); + let wr = is_useful(handler, engines, factory, &s_c_p, s_c_q, span)?; witness_report = WitnessReport::join_witness_reports(witness_report, wr); } - ok(witness_report, warnings, errors) + Ok(witness_report) } /// Computes a witness report from *U(P, q)* when *q* is an or-pattern @@ -603,22 +479,15 @@ fn is_useful_constructed( /// 2. Compute the witnesses from *U(P, q')* /// 3. Aggregate the witnesses from every *U(P, q')* fn is_useful_or( + handler: &Handler, engines: &Engines, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, pats: PatStack, span: &Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - - let (_, q_rest) = check!( - q.split_first(span), - return err(warnings, errors), - warnings, - errors - ); +) -> Result { + let (_, q_rest) = q.split_first(handler, span)?; let mut p = p.clone(); let mut witness_report = WitnessReport::Witnesses(PatStack::empty()); for pat in pats.into_iter() { @@ -627,18 +496,13 @@ fn is_useful_or( v.append(&mut q_rest.clone()); // 2. Compute the witnesses from *U(P, q')* - let wr = check!( - is_useful(engines, factory, &p, &v, span), - return err(warnings, errors), - warnings, - errors - ); + let wr = is_useful(handler, engines, factory, &p, &v, span)?; p.push(v); // 3. Aggregate the witnesses from every *U(P, q')* witness_report = WitnessReport::join_witness_reports(witness_report, wr); } - ok(witness_report, warnings, errors) + Ok(witness_report) } /// Given a `Matrix` *P*, constructs the default `Matrix` *D(P). This is done by @@ -647,32 +511,24 @@ fn is_useful_or( /// Intuition: A default `Matrix` is a transformation upon *P* that "shrinks" /// the rows of *P* depending on if the row is able to generally match all /// patterns in a default case. -fn compute_default_matrix(p: &Matrix, q: &PatStack, span: &Span) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +fn compute_default_matrix( + handler: &Handler, + p: &Matrix, + q: &PatStack, + span: &Span, +) -> Result { let mut d_p = Matrix::empty(); for p_i in p.rows().iter() { - d_p.append(&mut check!( - compute_default_matrix_row(p_i, q, span), - return err(warnings, errors), - warnings, - errors - )); + d_p.append(&mut compute_default_matrix_row(handler, p_i, q, span)?); } - let (m, n) = check!( - d_p.m_n(span), - return err(warnings, errors), - warnings, - errors - ); + let (m, n) = d_p.m_n(handler, span)?; if m > 0 && n != (q.len() - 1) { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "D(P) matrix is misshapen", span.clone(), - )); - return err(warnings, errors); + ))); } - ok(d_p, warnings, errors) + Ok(d_p) } /// Given a `PatStack` *pⁱ* from `Matrix` *P*, compute the resulting row of the @@ -701,19 +557,13 @@ fn compute_default_matrix(p: &Matrix, q: &PatStack, span: &Span) -> CompileResul /// 2. The resulting rows are the rows obtained from calling the recursive /// *D(P')* fn compute_default_matrix_row( + handler: &Handler, p_i: &PatStack, q: &PatStack, span: &Span, -) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result, ErrorEmitted> { let mut rows: Vec = vec![]; - let (p_i_1, mut p_i_rest) = check!( - p_i.split_first(span), - return err(warnings, errors), - warnings, - errors - ); + let (p_i_1, mut p_i_rest) = p_i.split_first(handler, span)?; match p_i_1 { Pattern::Wildcard => { // 2. *pⁱ₁* is a wildcard pattern: @@ -734,19 +584,14 @@ fn compute_default_matrix_row( } // 2. The resulting rows are the rows obtained from calling the recursive // *D(P')* - let d_p = check!( - compute_default_matrix(&m, q, span), - return err(warnings, errors), - warnings, - errors - ); + let d_p = compute_default_matrix(handler, &m, q, span)?; rows.append(&mut d_p.into_rows()); } // 1. *pⁱ₁* is a constructed pattern *c'(r₁, ..., rₐ)*: // 1. no row is produced _ => {} } - ok(rows, warnings, errors) + Ok(rows) } /// Given a constructor *c* and a `Matrix` *P*, constructs the specialized @@ -756,52 +601,36 @@ fn compute_default_matrix_row( /// Intuition: A specialized `Matrix` is a transformation upon *P* that /// "unwraps" the rows of *P* depending on if they are congruent with *c*. fn compute_specialized_matrix( + handler: &Handler, c: &Pattern, p: &Matrix, q: &PatStack, span: &Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result { let mut s_c_p = Matrix::empty(); if let Pattern::Or(cpats) = c { for cpat in cpats.iter() { - let mut rows = check!( - compute_specialized_matrix(cpat, p, q, span), - return err(warnings, errors), - warnings, - errors - ) - .into_rows(); + let mut rows = compute_specialized_matrix(handler, cpat, p, q, span)?.into_rows(); s_c_p.append(&mut rows); } - return ok(s_c_p, warnings, errors); + return Ok(s_c_p); } for p_i in p.rows().iter() { - s_c_p.append(&mut check!( - compute_specialized_matrix_row(c, p_i, q, span), - return err(warnings, errors), - warnings, - errors - )); + s_c_p.append(&mut compute_specialized_matrix_row( + handler, c, p_i, q, span, + )?); } - let (m, n) = check!( - s_c_p.m_n(span), - return err(warnings, errors), - warnings, - errors - ); + let (m, n) = s_c_p.m_n(handler, span)?; if m > 0 && n != (c.a() + q.len() - 1) { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "S(c,P) matrix is misshapen", span.clone(), - )); - return err(warnings, errors); + ))); } - ok(s_c_p, warnings, errors) + Ok(s_c_p) } /// Given a constructor *c* and a `PatStack` *pⁱ* from `Matrix` *P*, compute the @@ -835,20 +664,14 @@ fn compute_specialized_matrix( /// 2. The resulting rows are the rows obtained from calling the recursive /// *S(c, P')* fn compute_specialized_matrix_row( + handler: &Handler, c: &Pattern, p_i: &PatStack, q: &PatStack, span: &Span, -) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result, ErrorEmitted> { let mut rows: Vec = vec![]; - let (p_i_1, mut p_i_rest) = check!( - p_i.split_first(span), - return err(warnings, errors), - warnings, - errors - ); + let (p_i_1, mut p_i_rest) = p_i.split_first(handler, span)?; match p_i_1 { Pattern::Wildcard => { // 3. *pⁱ₁* is a wildcard pattern and the number of sub-patterns in *c* is *a*: @@ -870,24 +693,14 @@ fn compute_specialized_matrix_row( // 4.2. The resulting rows are the rows obtained from calling the recursive // *S(c, P')* - let s_c_p = check!( - compute_specialized_matrix(c, &m, q, span), - return err(warnings, errors), - warnings, - errors - ); + let s_c_p = compute_specialized_matrix(handler, c, &m, q, span)?; rows.append(&mut s_c_p.into_rows()); } other => { if c.has_the_same_constructor(&other) { // 1. *pⁱ₁* is a constructed pattern *c'(r₁, ..., rₐ)* where *c* == *c'*: // 1.1. the resulting row equals \[*r₁ ... rₐ pⁱ₂ ... pⁱₙ*\] - let mut row: PatStack = check!( - other.sub_patterns(span), - return err(warnings, errors), - warnings, - errors - ); + let mut row: PatStack = other.sub_patterns(handler, span)?; row.append(&mut p_i_rest); rows.push(row); } @@ -895,5 +708,5 @@ fn compute_specialized_matrix_row( // 2.1. no row is produced } } - ok(rows, warnings, errors) + Ok(rows) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/witness_report.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/witness_report.rs index c01de018f18..8335b4342bf 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/witness_report.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/witness_report.rs @@ -1,12 +1,10 @@ use std::fmt; use itertools::Itertools; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; -use crate::{ - error::{err, ok}, - CompileError, CompileResult, -}; +use crate::CompileError; use super::{patstack::PatStack, pattern::Pattern}; @@ -43,53 +41,39 @@ impl WitnessReport { /// *wr'* is created by taking the remaining elements of *wr* after *a* /// elements have been removed from the front of *wr*. pub(crate) fn split_into_leading_constructor( + handler: &Handler, witness_report: WitnessReport, c: &Pattern, span: &Span, - ) -> CompileResult<(Pattern, Self)> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result<(Pattern, Self), ErrorEmitted> { match witness_report { - WitnessReport::NoWitnesses => { - errors.push(CompileError::Internal( - "expected to find witnesses to use as arguments to a constructor", - span.clone(), - )); - err(warnings, errors) - } + WitnessReport::NoWitnesses => Err(handler.emit_err(CompileError::Internal( + "expected to find witnesses to use as arguments to a constructor", + span.clone(), + ))), WitnessReport::Witnesses(witnesses) => { - let (rs, ps) = check!( - witnesses.split_at(c.a(), span), - return err(warnings, errors), - warnings, - errors - ); - let pat = check!( - Pattern::from_constructor_and_arguments(c, rs, span), - return err(warnings, errors), - warnings, - errors - ); - ok((pat, WitnessReport::Witnesses(ps)), warnings, errors) + let (rs, ps) = witnesses.split_at(handler, c.a(), span)?; + let pat = Pattern::from_constructor_and_arguments(handler, c, rs, span)?; + Ok((pat, WitnessReport::Witnesses(ps))) } } } /// Prepends a witness `Pattern` onto the `WitnessReport`. - pub(crate) fn add_witness(&mut self, witness: Pattern, span: &Span) -> CompileResult<()> { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn add_witness( + &mut self, + handler: &Handler, + witness: Pattern, + span: &Span, + ) -> Result<(), ErrorEmitted> { match self { - WitnessReport::NoWitnesses => { - errors.push(CompileError::Internal( - "expected to find witnesses", - span.clone(), - )); - err(warnings, errors) - } + WitnessReport::NoWitnesses => Err(handler.emit_err(CompileError::Internal( + "expected to find witnesses", + span.clone(), + ))), WitnessReport::Witnesses(witnesses) => { witnesses.prepend(witness); - ok((), warnings, errors) + Ok(()) } } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs index 7f47bae7ae4..c6cc5d6b829 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs @@ -1,5 +1,4 @@ use crate::{ - error::{err, ok}, language::{ty, CallPath, Literal}, semantic_analysis::{ ast_node::expression::typed_expression::{ @@ -8,10 +7,13 @@ use crate::{ }, TypeCheckContext, }, - CompileResult, Ident, TypeId, + Ident, TypeId, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::span::Span; use itertools::{EitherOrBoth, Itertools}; @@ -107,12 +109,11 @@ pub(crate) type MatcherResult = (MatchReqMap, MatchDeclMap); /// [] /// ``` pub(crate) fn matcher( + handler: &Handler, mut ctx: TypeCheckContext, exp: &ty::TyExpression, scrutinee: ty::TyScrutinee, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result { let ty::TyScrutinee { variant, type_id, @@ -123,12 +124,17 @@ pub(crate) fn matcher( let engines = ctx.engines(); // unify the type of the scrutinee with the type of the expression - check!( - CompileResult::from(type_engine.unify(engines, type_id, exp.return_type, &span, "", None)), - return err(warnings, errors), - warnings, - errors - ); + let mut error_emitted = None; + let (warnings, errors) = type_engine.unify(engines, type_id, exp.return_type, &span, "", None); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + error_emitted = Some(handler.emit_err(err)); + } + if let Some(err) = error_emitted { + return Err(err); + } match variant { ty::TyScrutineeVariant::Or(elems) => { @@ -137,12 +143,8 @@ pub(crate) fn matcher( for scrutinee in elems { let scrutinee_span = scrutinee.span.clone(); - let (new_req_map, mut new_decl_map) = check!( - matcher(ctx.by_ref(), exp, scrutinee), - return err(warnings, errors), - warnings, - errors - ); + let (new_req_map, mut new_decl_map) = + matcher(handler, ctx.by_ref(), exp, scrutinee)?; // check that the bindings are the same between clauses @@ -162,11 +164,12 @@ pub(crate) fn matcher( Right((ident, _)) => Some(ident), }; if let Some(var) = missing_var { - errors.push(CompileError::MatchVariableNotBoundInAllPatterns { - var: var.clone(), - span: scrutinee_span, - }); - return err(warnings, errors); + return Err(handler.emit_err( + CompileError::MatchVariableNotBoundInAllPatterns { + var: var.clone(), + span: scrutinee_span, + }, + )); } } } @@ -174,35 +177,31 @@ pub(crate) fn matcher( match_decl_map = Some(new_decl_map); match_req_map = factor_or_on_cnf(match_req_map, new_req_map); } - ok( - (match_req_map, match_decl_map.unwrap_or(vec![])), - vec![], - vec![], - ) - } - ty::TyScrutineeVariant::CatchAll => ok((vec![], vec![]), vec![], vec![]), - ty::TyScrutineeVariant::Literal(value) => { - ok(match_literal(exp, value, span), vec![], vec![]) + Ok((match_req_map, match_decl_map.unwrap_or(vec![]))) } - ty::TyScrutineeVariant::Variable(name) => ok(match_variable(exp, name), vec![], vec![]), - ty::TyScrutineeVariant::Constant(name, _, const_decl) => ok( - match_constant(ctx, exp, name, const_decl.type_ascription.type_id, span), - vec![], - vec![], - ), + ty::TyScrutineeVariant::CatchAll => Ok((vec![], vec![])), + ty::TyScrutineeVariant::Literal(value) => Ok(match_literal(exp, value, span)), + ty::TyScrutineeVariant::Variable(name) => Ok(match_variable(exp, name)), + ty::TyScrutineeVariant::Constant(name, _, const_decl) => Ok(match_constant( + ctx, + exp, + name, + const_decl.type_ascription.type_id, + span, + )), ty::TyScrutineeVariant::StructScrutinee { struct_ref: _, fields, .. - } => match_struct(ctx, exp, fields), + } => match_struct(handler, ctx, exp, fields), ty::TyScrutineeVariant::EnumScrutinee { enum_ref: _, variant, call_path_decl, value, .. - } => match_enum(ctx, exp, *variant, call_path_decl, *value, span), - ty::TyScrutineeVariant::Tuple(elems) => match_tuple(ctx, exp, elems, span), + } => match_enum(handler, ctx, exp, *variant, call_path_decl, *value, span), + ty::TyScrutineeVariant::Tuple(elems) => match_tuple(handler, ctx, exp, elems, span), } } @@ -269,12 +268,11 @@ fn match_constant( } fn match_struct( + handler: &Handler, mut ctx: TypeCheckContext, exp: &ty::TyExpression, fields: Vec, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result { let mut match_req_map = vec![]; let mut match_decl_map = vec![]; for ty::TyStructScrutineeField { @@ -284,12 +282,13 @@ fn match_struct( field_def_name: _, } in fields.into_iter() { - let subfield = check!( - instantiate_struct_field_access(ctx.engines(), exp.clone(), field.clone(), field_span), - return err(warnings, errors), - warnings, - errors - ); + let subfield = instantiate_struct_field_access( + handler, + ctx.engines(), + exp.clone(), + field.clone(), + field_span, + )?; match scrutinee { // if the scrutinee is simply naming the struct field ... None => { @@ -297,74 +296,56 @@ fn match_struct( } // or if the scrutinee has a more complex agenda Some(scrutinee) => { - let (mut new_match_req_map, mut new_match_decl_map) = check!( - matcher(ctx.by_ref(), &subfield, scrutinee), - return err(warnings, errors), - warnings, - errors - ); + let (mut new_match_req_map, mut new_match_decl_map) = + matcher(handler, ctx.by_ref(), &subfield, scrutinee)?; match_req_map.append(&mut new_match_req_map); match_decl_map.append(&mut new_match_decl_map); } } } - ok((match_req_map, match_decl_map), warnings, errors) + Ok((match_req_map, match_decl_map)) } fn match_enum( + handler: &Handler, ctx: TypeCheckContext, exp: &ty::TyExpression, variant: ty::TyEnumVariant, call_path_decl: ty::TyDecl, scrutinee: ty::TyScrutinee, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result { let (mut match_req_map, unsafe_downcast) = instantiate_unsafe_downcast(ctx.engines(), exp, variant, call_path_decl, span); - let (mut new_match_req_map, match_decl_map) = check!( - matcher(ctx, &unsafe_downcast, scrutinee), - return err(warnings, errors), - warnings, - errors - ); + let (mut new_match_req_map, match_decl_map) = + matcher(handler, ctx, &unsafe_downcast, scrutinee)?; match_req_map.append(&mut new_match_req_map); - ok((match_req_map, match_decl_map), warnings, errors) + Ok((match_req_map, match_decl_map)) } fn match_tuple( + handler: &Handler, mut ctx: TypeCheckContext, exp: &ty::TyExpression, elems: Vec, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result { let mut match_req_map = vec![]; let mut match_decl_map = vec![]; for (pos, elem) in elems.into_iter().enumerate() { - let tuple_index_access = check!( - instantiate_tuple_index_access( - ctx.engines(), - exp.clone(), - pos, - span.clone(), - span.clone() - ), - return err(warnings, errors), - warnings, - errors - ); - let (mut new_match_req_map, mut new_match_decl_map) = check!( - matcher(ctx.by_ref(), &tuple_index_access, elem), - return err(warnings, errors), - warnings, - errors - ); + let tuple_index_access = instantiate_tuple_index_access( + handler, + ctx.engines(), + exp.clone(), + pos, + span.clone(), + span.clone(), + )?; + let (mut new_match_req_map, mut new_match_decl_map) = + matcher(handler, ctx.by_ref(), &tuple_index_access, elem)?; match_req_map.append(&mut new_match_req_map); match_decl_map.append(&mut new_match_decl_map); } - ok((match_req_map, match_decl_map), warnings, errors) + Ok((match_req_map, match_decl_map)) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index 94e6e0cefb8..8669df1e19a 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -1,24 +1,22 @@ +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Spanned; use crate::{ - error::{err, ok}, language::{parsed::MatchBranch, ty}, semantic_analysis::*, types::DeterministicallyAborts, - CompileResult, TypeInfo, + TypeInfo, }; use super::matcher::matcher; impl ty::TyMatchBranch { pub(crate) fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, typed_value: &ty::TyExpression, branch: MatchBranch, - ) -> CompileResult<(ty::TyMatchBranch, ty::TyScrutinee)> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(ty::TyMatchBranch, ty::TyScrutinee), ErrorEmitted> { let MatchBranch { scrutinee, result, @@ -30,20 +28,11 @@ impl ty::TyMatchBranch { let engines = ctx.engines(); // type check the scrutinee - let typed_scrutinee = check!( - ty::TyScrutinee::type_check(ctx.by_ref(), scrutinee), - return err(warnings, errors), - warnings, - errors - ); + let typed_scrutinee = ty::TyScrutinee::type_check(handler, ctx.by_ref(), scrutinee)?; // calculate the requirements map and the declarations map - let (match_req_map, match_decl_map) = check!( - matcher(ctx.by_ref(), typed_value, typed_scrutinee.clone(),), - return err(warnings, errors), - warnings, - errors - ); + let (match_req_map, match_decl_map) = + matcher(handler, ctx.by_ref(), typed_value, typed_scrutinee.clone())?; // create a new namespace for this branch let mut namespace = ctx.namespace.clone(); @@ -63,7 +52,7 @@ impl ty::TyMatchBranch { return_type, type_ascription, })); - ctx.insert_symbol(left_decl, var_decl.clone()); + let _ = ctx.insert_symbol(handler, left_decl, var_decl.clone()); code_block_contents.push(ty::TyAstNode { content: ty::TyAstNodeContent::Declaration(var_decl), span, @@ -75,21 +64,19 @@ impl ty::TyMatchBranch { let ctx = ctx .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - check!( - ty::TyExpression::type_check(ctx, result), - return err(warnings, errors), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, result)? }; // unify the return type from the typed result with the type annotation if !typed_result.deterministically_aborts(decl_engine, true) { - append!( - ctx.unify_with_self(typed_result.return_type, &typed_result.span), - warnings, - errors - ); + let (warnings, errors) = + ctx.unify_with_self(typed_result.return_type, &typed_result.span); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } } // if the typed branch result is a code block, then add the contents @@ -133,6 +120,6 @@ impl ty::TyMatchBranch { result: new_result, span: branch_span, }; - ok((typed_branch, typed_scrutinee), warnings, errors) + Ok((typed_branch, typed_scrutinee)) } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs index f7dc713f770..56f322207dd 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs @@ -1,7 +1,7 @@ +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; use crate::{ - error::{err, ok}, language::{parsed::*, ty, *}, semantic_analysis::{ ast_node::expression::typed_expression::{ @@ -9,37 +9,39 @@ use crate::{ }, TypeCheckContext, }, - CompileError, CompileResult, TypeInfo, + CompileError, TypeInfo, }; impl ty::TyMatchExpression { pub(crate) fn type_check( + handler: &Handler, ctx: TypeCheckContext, typed_value: ty::TyExpression, branches: Vec, span: Span, - ) -> CompileResult<(ty::TyMatchExpression, Vec)> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(ty::TyMatchExpression, Vec), ErrorEmitted> { // type check all of the branches let mut typed_branches = vec![]; let mut typed_scrutinees = vec![]; let mut ctx = ctx.with_help_text("all branches of a match statement must return the same type"); + + let mut error_emitted = None; for branch in branches.into_iter() { - let (typed_branch, typed_scrutinee) = check!( - ty::TyMatchBranch::type_check(ctx.by_ref(), &typed_value, branch), - continue, - warnings, - errors - ); + let (typed_branch, typed_scrutinee) = + match ty::TyMatchBranch::type_check(handler, ctx.by_ref(), &typed_value, branch) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }; typed_branches.push(typed_branch); typed_scrutinees.push(typed_scrutinee); } - if !errors.is_empty() { - return err(warnings, errors); + if let Some(err) = error_emitted { + return Err(err); } let typed_exp = ty::TyMatchExpression { @@ -48,16 +50,14 @@ impl ty::TyMatchExpression { return_type_id: ctx.type_annotation(), span, }; - ok((typed_exp, typed_scrutinees), warnings, errors) + Ok((typed_exp, typed_scrutinees)) } pub(crate) fn convert_to_typed_if_expression( self, + handler: &Handler, mut ctx: TypeCheckContext, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -75,12 +75,18 @@ impl ty::TyMatchExpression { for (left_req, right_req) in disjunction.into_iter().rev() { let joined_span = Span::join(left_req.span.clone(), right_req.span.clone()); let args = vec![left_req, right_req]; - let new_condition = check!( - ty::TyExpression::core_ops_eq(ctx.by_ref(), args, joined_span), - continue, - warnings, - errors - ); + let new_condition = match ty::TyExpression::core_ops_eq( + handler, + ctx.by_ref(), + args, + joined_span, + ) { + Ok(res) => res, + Err(_) => { + continue; + } + }; + disj_conditional = Some(match disj_conditional { Some(inner_condition) => { let joined_span = Span::join( @@ -125,18 +131,19 @@ impl ty::TyMatchExpression { (None, Some(conditional)) => { // TODO: figure out if this argument matters or not let ctx = ctx.by_ref().with_type_annotation(self.return_type_id); - check!( - instantiate_if_expression( - ctx, - conditional, - result.clone(), - Some(result), // TODO: this is a really bad hack and we should not do this - result_span, - ), - continue, - warnings, - errors - ) + match instantiate_if_expression( + handler, + ctx, + conditional, + result.clone(), + Some(result), // TODO: this is a really bad hack and we should not do this + result_span, + ) { + Ok(res) => res, + Err(_) => { + continue; + } + } } (Some(prev_if_exp), None) => { let ctx = ctx.by_ref().with_type_annotation(self.return_type_id); @@ -145,33 +152,35 @@ impl ty::TyMatchExpression { return_type: type_engine.insert(engines, TypeInfo::Boolean), span: result_span.clone(), }; - check!( - instantiate_if_expression( - ctx, - conditional, - result, - Some(prev_if_exp), - result_span, - ), - continue, - warnings, - errors - ) + match instantiate_if_expression( + handler, + ctx, + conditional, + result, + Some(prev_if_exp), + result_span, + ) { + Ok(res) => res, + Err(_) => { + continue; + } + } } (Some(prev_if_exp), Some(conditional)) => { let ctx = ctx.by_ref().with_type_annotation(self.return_type_id); - check!( - instantiate_if_expression( - ctx, - conditional, - result, - Some(prev_if_exp), - result_span, - ), - continue, - warnings, - errors - ) + match instantiate_if_expression( + handler, + ctx, + conditional, + result, + Some(prev_if_exp), + result_span, + ) { + Ok(res) => res, + Err(_) => { + continue; + } + } } }); } @@ -215,16 +224,15 @@ impl ty::TyMatchExpression { return_type: self.return_type_id, span: self.span, }; - return ok(typed_if_exp, warnings, errors); + return Ok(typed_if_exp); } - errors.push(CompileError::Internal( + Err(handler.emit_err(CompileError::Internal( "unable to convert match exp to if exp", self.span, - )); - err(warnings, errors) + ))) } - Some(typed_if_exp) => ok(typed_if_exp, warnings, errors), + Some(typed_if_exp) => Ok(typed_if_exp), } } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index 236d71be361..2cdb02c1472 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -1,9 +1,11 @@ -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{BaseIdent, Ident, Span, Spanned}; use crate::{ decl_engine::DeclEngineInsert, - error::*, language::{ parsed::*, ty::{self, TyDecl}, @@ -15,11 +17,10 @@ use crate::{ impl ty::TyScrutinee { pub(crate) fn type_check( + handler: &Handler, mut ctx: TypeCheckContext, scrutinee: Scrutinee, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); match scrutinee { @@ -28,19 +29,18 @@ impl ty::TyScrutinee { let mut typed_elems = Vec::with_capacity(elems.len()); for scrutinee in elems { - typed_elems.push(check!( - ty::TyScrutinee::type_check(ctx.by_ref(), scrutinee), - return err(warnings, errors), - warnings, - errors, - )); + typed_elems.push(ty::TyScrutinee::type_check( + handler, + ctx.by_ref(), + scrutinee, + )?); } let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Or(typed_elems), type_id, span, }; - ok(typed_scrutinee, warnings, errors) + Ok(typed_scrutinee) } Scrutinee::CatchAll { span } => { let type_id = type_engine.insert(engines, TypeInfo::Unknown); @@ -57,7 +57,7 @@ impl ty::TyScrutinee { type_id: type_engine.insert(engines, TypeInfo::Placeholder(dummy_type_param)), span, }; - ok(typed_scrutinee, warnings, errors) + Ok(typed_scrutinee) } Scrutinee::Literal { value, span } => { let typed_scrutinee = ty::TyScrutinee { @@ -65,21 +65,22 @@ impl ty::TyScrutinee { type_id: type_engine.insert(engines, value.to_typeinfo()), span, }; - ok(typed_scrutinee, warnings, errors) + Ok(typed_scrutinee) } - Scrutinee::Variable { name, span } => type_check_variable(ctx, name, span), + Scrutinee::Variable { name, span } => type_check_variable(handler, ctx, name, span), Scrutinee::StructScrutinee { struct_name, fields, span, - } => type_check_struct(ctx, struct_name.suffix, fields, span), + } => type_check_struct(handler, ctx, struct_name.suffix, fields, span), Scrutinee::EnumScrutinee { call_path, value, span, - } => type_check_enum(ctx, call_path, *value, span), + } => type_check_enum(handler, ctx, call_path, *value, span), Scrutinee::AmbiguousSingleIdent(ident) => { let maybe_enum = type_check_enum( + &Handler::default(), ctx.by_ref(), CallPath { prefixes: vec![], @@ -96,48 +97,48 @@ impl ty::TyScrutinee { if maybe_enum.is_ok() { maybe_enum } else { - type_check_variable(ctx, ident.clone(), ident.span()) + type_check_variable(handler, ctx, ident.clone(), ident.span()) } } - Scrutinee::Tuple { elems, span } => type_check_tuple(ctx, elems, span), - Scrutinee::Error { .. } => err(vec![], vec![]), + Scrutinee::Tuple { elems, span } => type_check_tuple(handler, ctx, elems, span), + Scrutinee::Error { .. } => Err(ErrorEmitted), } } } fn type_check_variable( + handler: &Handler, ctx: TypeCheckContext, name: Ident, span: Span, -) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); - let typed_scrutinee = match ctx.namespace.resolve_symbol(&name).value { + let typed_scrutinee = match ctx + .namespace + .resolve_symbol(&Handler::default(), &name) + .ok() + { // If this variable is a constant, then we turn it into a [TyScrutinee::Constant](ty::TyScrutinee::Constant). Some(ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. })) => { let constant_decl = decl_engine.get_constant(decl_id); let value = match constant_decl.value { Some(ref value) => value, None => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "constant value does not contain expression", span, - )); - return err(warnings, errors); + ))); } }; let literal = match value.extract_literal_value() { Some(value) => value, None => { - errors.push(CompileError::Unimplemented( + return Err(handler.emit_err(CompileError::Unimplemented( "constant values of this type are not supported yet", span, - )); - return err(warnings, errors); + ))); } }; ty::TyScrutinee { @@ -154,48 +155,35 @@ fn type_check_variable( }, }; - ok(typed_scrutinee, warnings, errors) + Ok(typed_scrutinee) } fn type_check_struct( + handler: &Handler, mut ctx: TypeCheckContext, struct_name: Ident, fields: Vec, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); // find the struct definition from the name - let unknown_decl = check!( - ctx.namespace.resolve_symbol(&struct_name).cloned(), - return err(warnings, errors), - warnings, - errors - ); - let struct_ref = check!( - unknown_decl.to_struct_ref(ctx.engines()), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = ctx + .namespace + .resolve_symbol(handler, &struct_name) + .cloned()?; + let struct_ref = unknown_decl.to_struct_ref(handler, ctx.engines())?; let mut struct_decl = decl_engine.get_struct(&struct_ref); // monomorphize the struct definition - check!( - ctx.monomorphize( - &mut struct_decl, - &mut [], - EnforceTypeArguments::No, - &struct_name.span() - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut struct_decl, + &mut [], + EnforceTypeArguments::No, + &struct_name.span(), + )?; // type check the fields let mut typed_fields = vec![]; @@ -209,21 +197,15 @@ fn type_check_struct( span, } => { // ensure that the struct definition has this field - let struct_field = check!( - struct_decl.expect_field(&field), - return err(warnings, errors), - warnings, - errors - ); + let struct_field = struct_decl.expect_field(handler, &field)?; // type check the nested scrutinee let typed_scrutinee = match scrutinee { None => None, - Some(scrutinee) => Some(check!( - ty::TyScrutinee::type_check(ctx.by_ref(), scrutinee), - return err(warnings, errors), - warnings, - errors - )), + Some(scrutinee) => Some(ty::TyScrutinee::type_check( + handler, + ctx.by_ref(), + scrutinee, + )?), }; typed_fields.push(ty::TyStructScrutineeField { field, @@ -244,12 +226,12 @@ fn type_check_struct( .map(|f| f.name.to_string()) .collect::>(); - errors.push(CompileError::MatchStructPatternMissingFields { - span, - missing_fields, - }); - - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MatchStructPatternMissingFields { + span, + missing_fields, + }), + ); } let struct_ref = decl_engine.insert(struct_decl); @@ -267,18 +249,16 @@ fn type_check_struct( }, }; - ok(typed_scrutinee, warnings, errors) + Ok(typed_scrutinee) } fn type_check_enum( + handler: &Handler, mut ctx: TypeCheckContext, call_path: CallPath, value: Scrutinee, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -292,18 +272,11 @@ fn type_check_enum( is_absolute: call_path.is_absolute, }; // find the enum definition from the name - let unknown_decl = check!( - ctx.namespace.resolve_call_path(&enum_callpath).cloned(), - return err(warnings, errors), - warnings, - errors - ); - let enum_ref = check!( - unknown_decl.to_enum_ref(ctx.engines()), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = ctx + .namespace + .resolve_call_path(handler, &enum_callpath) + .cloned()?; + let enum_ref = unknown_decl.to_enum_ref(handler, ctx.engines())?; ( enum_callpath.span(), decl_engine.get_enum(&enum_ref), @@ -312,12 +285,10 @@ fn type_check_enum( } None => { // we may have an imported variant - let decl = check!( - ctx.namespace.resolve_call_path(&call_path).cloned(), - return err(warnings, errors), - warnings, - errors - ); + let decl = ctx + .namespace + .resolve_call_path(handler, &call_path) + .cloned()?; if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl { enum_ref, .. }) = decl.clone() { ( call_path.suffix.span(), @@ -325,44 +296,31 @@ fn type_check_enum( decl, ) } else { - errors.push(CompileError::EnumNotFound { + return Err(handler.emit_err(CompileError::EnumNotFound { name: call_path.suffix.clone(), span: call_path.suffix.span(), - }); - return err(warnings, errors); + })); } } }; let variant_name = call_path.suffix.clone(); // monomorphize the enum definition - check!( - ctx.monomorphize( - &mut enum_decl, - &mut [], - EnforceTypeArguments::No, - &callsite_span, - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut enum_decl, + &mut [], + EnforceTypeArguments::No, + &callsite_span, + )?; // check to see if the variant exists and grab it if it does - let variant = check!( - enum_decl.expect_variant_from_name(&variant_name).cloned(), - return err(warnings, errors), - warnings, - errors - ); + let variant = enum_decl + .expect_variant_from_name(handler, &variant_name) + .cloned()?; // type check the nested scrutinee - let typed_value = check!( - ty::TyScrutinee::type_check(ctx, value), - return err(warnings, errors), - warnings, - errors - ); + let typed_value = ty::TyScrutinee::type_check(handler, ctx, value)?; let enum_ref = decl_engine.insert(enum_decl); let typed_scrutinee = ty::TyScrutinee { @@ -377,28 +335,26 @@ fn type_check_enum( span, }; - ok(typed_scrutinee, warnings, errors) + Ok(typed_scrutinee) } fn type_check_tuple( + handler: &Handler, mut ctx: TypeCheckContext, elems: Vec, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let mut typed_elems = vec![]; for elem in elems.into_iter() { - typed_elems.push(check!( - ty::TyScrutinee::type_check(ctx.by_ref(), elem), - continue, - warnings, - errors - )); + typed_elems.push( + match ty::TyScrutinee::type_check(handler, ctx.by_ref(), elem) { + Ok(res) => res, + Err(_) => continue, + }, + ); } let type_id = type_engine.insert( engines, @@ -420,5 +376,5 @@ fn type_check_tuple( span, }; - ok(typed_scrutinee, warnings, errors) + Ok(typed_scrutinee) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index fda40b8f681..1ebc9533dbb 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -19,7 +19,6 @@ pub(crate) use self::{ use crate::{ asm_lang::{virtual_ops::VirtualOp, virtual_register::VirtualRegister}, decl_engine::*, - error::*, language::{ parsed::*, ty::{self, TyImplItem}, @@ -36,6 +35,7 @@ use sway_ast::intrinsics::Intrinsic; use sway_error::{ convert_parse_tree_error::ConvertParseTreeError, error::CompileError, + handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; use sway_types::{integer_bits::IntegerBits, Ident, Named, Span, Spanned}; @@ -47,13 +47,11 @@ use std::collections::{HashMap, VecDeque}; #[allow(clippy::too_many_arguments)] impl ty::TyExpression { pub(crate) fn core_ops_eq( + handler: &Handler, ctx: TypeCheckContext, arguments: Vec, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let decl_engine = ctx.engines.de(); let call_path = CallPath { @@ -76,20 +74,11 @@ impl ty::TyExpression { span: call_path.span(), }; let arguments = VecDeque::from(arguments); - let (decl_ref, _) = check!( - resolve_method_name(ctx, &mut method_name_binding, arguments.clone()), - return err(warnings, errors), - warnings, - errors - ); + let (decl_ref, _) = + resolve_method_name(handler, ctx, &mut method_name_binding, arguments.clone())?; let method = decl_engine.get_function(&decl_ref); // check that the number of parameters and the number of the arguments is the same - check!( - check_function_arguments_arity(arguments.len(), &method, &call_path, false), - return err(warnings, errors), - warnings, - errors - ); + check_function_arguments_arity(handler, arguments.len(), &method, &call_path, false)?; let return_type = method.return_type; let args_and_names = method .parameters @@ -110,18 +99,22 @@ impl ty::TyExpression { return_type: return_type.type_id, span, }; - ok(exp, warnings, errors) + Ok(exp) } - pub(crate) fn type_check(mut ctx: TypeCheckContext, expr: Expression) -> CompileResult { + pub(crate) fn type_check( + handler: &Handler, + mut ctx: TypeCheckContext, + expr: Expression, + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let expr_span = expr.span(); let span = expr_span.clone(); let res = match expr.kind { // We've already emitted an error for the `::Error` case. - ExpressionKind::Error(_) => ok(ty::TyExpression::error(span, engines), vec![], vec![]), - ExpressionKind::Literal(lit) => Self::type_check_literal(engines, lit, span), + ExpressionKind::Error(_) => Ok(ty::TyExpression::error(span, engines)), + ExpressionKind::Literal(lit) => Ok(Self::type_check_literal(engines, lit, span)), ExpressionKind::AmbiguousVariableExpression(name) => { let call_path = CallPath { prefixes: vec![], @@ -129,10 +122,13 @@ impl ty::TyExpression { is_absolute: false, }; if matches!( - ctx.namespace.resolve_call_path(&call_path).value, + ctx.namespace + .resolve_call_path(&Handler::default(), &call_path) + .ok(), Some(ty::TyDecl::EnumVariantDecl { .. }) ) { Self::type_check_delineated_path( + handler, ctx.by_ref(), TypeBinding { span: call_path.span(), @@ -143,11 +139,11 @@ impl ty::TyExpression { None, ) } else { - Self::type_check_variable_expression(ctx.by_ref(), name, span) + Self::type_check_variable_expression(handler, ctx.by_ref(), name, span) } } ExpressionKind::Variable(name) => { - Self::type_check_variable_expression(ctx.by_ref(), name, span) + Self::type_check_variable_expression(handler, ctx.by_ref(), name, span) } ExpressionKind::FunctionApplication(function_application_expression) => { let FunctionApplicationExpression { @@ -155,6 +151,7 @@ impl ty::TyExpression { arguments, } = *function_application_expression; Self::type_check_function_application( + handler, ctx.by_ref(), call_path_binding, arguments, @@ -165,10 +162,10 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean)); - Self::type_check_lazy_operator(ctx, op, *lhs, *rhs, span) + Self::type_check_lazy_operator(handler, ctx, op, *lhs, *rhs, span) } ExpressionKind::CodeBlock(contents) => { - Self::type_check_code_block(ctx.by_ref(), contents, span) + Self::type_check_code_block(handler, ctx.by_ref(), contents, span) } // TODO if _condition_ is constant, evaluate it and compile this to an // expression with only one branch @@ -177,6 +174,7 @@ impl ty::TyExpression { then, r#else, }) => Self::type_check_if_expression( + handler, ctx.by_ref().with_help_text(""), *condition, *then, @@ -185,26 +183,33 @@ impl ty::TyExpression { ), ExpressionKind::Match(MatchExpression { value, branches }) => { Self::type_check_match_expression( + handler, ctx.by_ref().with_help_text(""), *value, branches, span, ) } - ExpressionKind::Asm(asm) => Self::type_check_asm_expression(ctx.by_ref(), *asm, span), + ExpressionKind::Asm(asm) => { + Self::type_check_asm_expression(handler, ctx.by_ref(), *asm, span) + } ExpressionKind::Struct(struct_expression) => { let StructExpression { call_path_binding, fields, } = *struct_expression; - struct_instantiation(ctx.by_ref(), call_path_binding, fields, span) + struct_instantiation(handler, ctx.by_ref(), call_path_binding, fields, span) } ExpressionKind::Subfield(SubfieldExpression { prefix, field_to_access, - }) => { - Self::type_check_subfield_expression(ctx.by_ref(), *prefix, span, field_to_access) - } + }) => Self::type_check_subfield_expression( + handler, + ctx.by_ref(), + *prefix, + span, + field_to_access, + ), ExpressionKind::MethodApplication(method_application_expression) => { let MethodApplicationExpression { method_name_binding, @@ -212,6 +217,7 @@ impl ty::TyExpression { arguments, } = *method_application_expression; type_check_method_application( + handler, ctx.by_ref(), method_name_binding, contract_call_params, @@ -219,12 +225,21 @@ impl ty::TyExpression { span, ) } - ExpressionKind::Tuple(fields) => Self::type_check_tuple(ctx.by_ref(), fields, span), + ExpressionKind::Tuple(fields) => { + Self::type_check_tuple(handler, ctx.by_ref(), fields, span) + } ExpressionKind::TupleIndex(TupleIndexExpression { prefix, index, index_span, - }) => Self::type_check_tuple_index(ctx.by_ref(), *prefix, index, index_span, span), + }) => Self::type_check_tuple_index( + handler, + ctx.by_ref(), + *prefix, + index, + index_span, + span, + ), ExpressionKind::AmbiguousPathExpression(e) => { let AmbiguousPathExpression { call_path_binding, @@ -232,6 +247,7 @@ impl ty::TyExpression { qualified_path_root, } = *e; Self::type_check_ambiguous_path( + handler, ctx.by_ref(), call_path_binding, span, @@ -244,21 +260,27 @@ impl ty::TyExpression { call_path_binding, args, } = *delineated_path_expression; - Self::type_check_delineated_path(ctx.by_ref(), call_path_binding, span, args) + Self::type_check_delineated_path( + handler, + ctx.by_ref(), + call_path_binding, + span, + args, + ) } ExpressionKind::AbiCast(abi_cast_expression) => { let AbiCastExpression { abi_name, address } = *abi_cast_expression; - Self::type_check_abi_cast(ctx.by_ref(), abi_name, *address, span) + Self::type_check_abi_cast(handler, ctx.by_ref(), abi_name, *address, span) } ExpressionKind::Array(array_expression) => { - Self::type_check_array(ctx.by_ref(), array_expression.contents, span) + Self::type_check_array(handler, ctx.by_ref(), array_expression.contents, span) } ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { let ctx = ctx .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) .with_help_text(""); - Self::type_check_array_index(ctx, *prefix, *index, span) + Self::type_check_array_index(handler, ctx, *prefix, *index, span) } ExpressionKind::StorageAccess(StorageAccessExpression { field_names, @@ -268,15 +290,27 @@ impl ty::TyExpression { .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) .with_help_text(""); - Self::type_check_storage_access(ctx, field_names, storage_keyword_span, &span) + Self::type_check_storage_access( + handler, + ctx, + field_names, + storage_keyword_span, + &span, + ) } ExpressionKind::IntrinsicFunction(IntrinsicFunctionExpression { kind_binding, arguments, .. - }) => Self::type_check_intrinsic_function(ctx.by_ref(), kind_binding, arguments, span), + }) => Self::type_check_intrinsic_function( + handler, + ctx.by_ref(), + kind_binding, + arguments, + span, + ), ExpressionKind::WhileLoop(WhileLoopExpression { condition, body }) => { - Self::type_check_while_loop(ctx.by_ref(), *condition, body, span) + Self::type_check_while_loop(handler, ctx.by_ref(), *condition, body, span) } ExpressionKind::Break => { let expr = ty::TyExpression { @@ -284,7 +318,7 @@ impl ty::TyExpression { return_type: type_engine.insert(engines, TypeInfo::Unknown), span, }; - ok(expr, vec![], vec![]) + Ok(expr) } ExpressionKind::Continue => { let expr = ty::TyExpression { @@ -292,10 +326,10 @@ impl ty::TyExpression { return_type: type_engine.insert(engines, TypeInfo::Unknown), span, }; - ok(expr, vec![], vec![]) + Ok(expr) } ExpressionKind::Reassignment(ReassignmentExpression { lhs, rhs }) => { - Self::type_check_reassignment(ctx.by_ref(), lhs, *rhs, span) + Self::type_check_reassignment(handler, ctx.by_ref(), lhs, *rhs, span) } ExpressionKind::Return(expr) => { let ctx = ctx @@ -313,50 +347,42 @@ impl ty::TyExpression { "Returned value must match up with the function return type \ annotation.", ); - let mut warnings = vec![]; - let mut errors = vec![]; let expr_span = expr.span(); - let expr = check!( - ty::TyExpression::type_check(ctx, *expr), - ty::TyExpression::error(expr_span, engines), - warnings, - errors, - ); + let expr = ty::TyExpression::type_check(handler, ctx, *expr) + .unwrap_or_else(|_| ty::TyExpression::error(expr_span, engines)); let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Return(Box::new(expr)), return_type: type_engine.insert(engines, TypeInfo::Unknown), // FIXME: This should be Yes? span, }; - ok(typed_expr, warnings, errors) + Ok(typed_expr) } }; - let mut typed_expression = match res.value { - Some(r) => r, - None => return res, + let mut typed_expression = match res { + Ok(r) => r, + Err(e) => return Err(e), }; - let mut warnings = res.warnings; - let mut errors = res.errors; // if the return type cannot be cast into the annotation type then it is a type error - append!( - ctx.unify_with_self(typed_expression.return_type, &expr_span), - warnings, - errors - ); + let (warnings, errors) = ctx.unify_with_self(typed_expression.return_type, &expr_span); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } // The annotation may result in a cast, which is handled in the type engine. - typed_expression.return_type = check!( - ctx.resolve_type_with_self( + typed_expression.return_type = ctx + .resolve_type_with_self( + handler, typed_expression.return_type, &expr_span, EnforceTypeArguments::No, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); // Literals of type Numeric can now be resolved if typed_expression.return_type is // an UnsignedInteger or a Numeric @@ -364,31 +390,23 @@ impl ty::TyExpression { if let Literal::Numeric(_) = lit { match type_engine.get(typed_expression.return_type) { TypeInfo::UnsignedInteger(_) | TypeInfo::Numeric => { - typed_expression = check!( - Self::resolve_numeric_literal( - ctx, - lit, - expr_span, - typed_expression.return_type - ), - return err(warnings, errors), - warnings, - errors - ) + typed_expression = Self::resolve_numeric_literal( + handler, + ctx, + lit, + expr_span, + typed_expression.return_type, + )? } _ => {} } } } - ok(typed_expression, warnings, errors) + Ok(typed_expression) } - fn type_check_literal( - engines: &Engines, - lit: Literal, - span: Span, - ) -> CompileResult { + fn type_check_literal(engines: &Engines, lit: Literal, span: Span) -> ty::TyExpression { let type_engine = engines.te(); let return_type = match &lit { Literal::String(s) => TypeInfo::Str(Length::new(s.as_str().len(), s.clone())), @@ -401,26 +419,27 @@ impl ty::TyExpression { Literal::B256(_) => TypeInfo::B256, }; let id = type_engine.insert(engines, return_type); - let exp = ty::TyExpression { + ty::TyExpression { expression: ty::TyExpressionVariant::Literal(lit), return_type: id, span, - }; - ok(exp, vec![], vec![]) + } } pub(crate) fn type_check_variable_expression( + handler: &Handler, ctx: TypeCheckContext, name: Ident, span: Span, - ) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); - let exp = match ctx.namespace.resolve_symbol(&name).value { + let exp = match ctx + .namespace + .resolve_symbol(&Handler::default(), &name) + .ok() + { Some(ty::TyDecl::VariableDecl(decl)) => { let ty::TyVariableDecl { name: decl_name, @@ -463,7 +482,7 @@ impl ty::TyExpression { } } Some(a) => { - errors.push(CompileError::NotAVariable { + handler.emit_err(CompileError::NotAVariable { name: name.clone(), what_it_is: a.friendly_type_name(), span, @@ -471,93 +490,82 @@ impl ty::TyExpression { ty::TyExpression::error(name.span(), engines) } None => { - errors.push(CompileError::UnknownVariable { + handler.emit_err(CompileError::UnknownVariable { var_name: name.clone(), span, }); ty::TyExpression::error(name.span(), engines) } }; - ok(exp, warnings, errors) + Ok(exp) } fn type_check_function_application( + handler: &Handler, mut ctx: TypeCheckContext, mut call_path_binding: TypeBinding, arguments: Vec, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { // Grab the fn declaration. - let (fn_ref, _, _): (DeclRefFunction, _, _) = check!( - TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()), - return err(warnings, errors), - warnings, - errors - ); - - instantiate_function_application(ctx, fn_ref, call_path_binding, Some(arguments), span) + let (fn_ref, _, _): (DeclRefFunction, _, _) = + TypeBinding::type_check(&mut call_path_binding, handler, ctx.by_ref())?; + + instantiate_function_application( + handler, + ctx, + fn_ref, + call_path_binding, + Some(arguments), + span, + ) } fn type_check_lazy_operator( + handler: &Handler, ctx: TypeCheckContext, op: LazyOp, lhs: Expression, rhs: Expression, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let mut ctx = ctx.with_help_text(""); let engines = ctx.engines(); - let typed_lhs = check!( - ty::TyExpression::type_check(ctx.by_ref(), lhs.clone()), - ty::TyExpression::error(lhs.span(), engines), - warnings, - errors - ); + let typed_lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(lhs.span(), engines)); - let typed_rhs = check!( - ty::TyExpression::type_check(ctx.by_ref(), rhs.clone()), - ty::TyExpression::error(rhs.span(), engines), - warnings, - errors - ); + let typed_rhs = ty::TyExpression::type_check(handler, ctx.by_ref(), rhs.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(rhs.span(), engines)); let type_annotation = ctx.type_annotation(); let exp = instantiate_lazy_operator(op, typed_lhs, typed_rhs, type_annotation, span); - ok(exp, warnings, errors) + Ok(exp) } fn type_check_code_block( + handler: &Handler, mut ctx: TypeCheckContext, contents: CodeBlock, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let (typed_block, block_return_type) = check!( - ty::TyCodeBlock::type_check(ctx.by_ref(), contents), - ( - ty::TyCodeBlock { contents: vec![] }, - type_engine.insert(engines, TypeInfo::Tuple(Vec::new())) - ), - warnings, - errors - ); + let (typed_block, block_return_type) = + ty::TyCodeBlock::type_check(handler, ctx.by_ref(), contents).unwrap_or_else(|_| { + ( + ty::TyCodeBlock { contents: vec![] }, + type_engine.insert(engines, TypeInfo::Tuple(Vec::new())), + ) + }); - append!( - ctx.unify_with_self(block_return_type, &span), - warnings, - errors - ); + let (warnings, errors) = ctx.unify_with_self(block_return_type, &span); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } let exp = ty::TyExpression { expression: ty::TyExpressionVariant::CodeBlock(ty::TyCodeBlock { @@ -566,20 +574,18 @@ impl ty::TyExpression { return_type: block_return_type, span, }; - ok(exp, warnings, errors) + Ok(exp) } #[allow(clippy::type_complexity)] fn type_check_if_expression( + handler: &Handler, mut ctx: TypeCheckContext, condition: Expression, then: Expression, r#else: Option, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -588,55 +594,36 @@ impl ty::TyExpression { .by_ref() .with_help_text("The condition of an if expression must be a boolean expression.") .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean)); - check!( - ty::TyExpression::type_check(ctx, condition.clone()), - ty::TyExpression::error(condition.span(), engines), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, condition.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(condition.span(), engines)) }; let then = { let ctx = ctx .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - check!( - ty::TyExpression::type_check(ctx, then.clone()), - ty::TyExpression::error(then.span(), engines), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, then.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(then.span(), engines)) }; let r#else = r#else.map(|expr| { let ctx = ctx .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - check!( - ty::TyExpression::type_check(ctx, expr.clone()), - ty::TyExpression::error(expr.span(), engines), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, expr.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(expr.span(), engines)) }); - let exp = check!( - instantiate_if_expression(ctx, condition, then, r#else, span,), - return err(warnings, errors), - warnings, - errors - ); - ok(exp, warnings, errors) + let exp = instantiate_if_expression(handler, ctx, condition, then, r#else, span)?; + Ok(exp) } fn type_check_match_expression( + handler: &Handler, mut ctx: TypeCheckContext, value: Expression, branches: Vec, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -646,71 +633,49 @@ impl ty::TyExpression { .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - check!( - ty::TyExpression::type_check(ctx, value.clone()), - ty::TyExpression::error(value.span(), engines), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, value.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(value.span(), engines)) }; let type_id = typed_value.return_type; // check to make sure that the type of the value is something that can be matched upon - check!( - type_engine - .get(type_id) - .expect_is_supported_in_match_expressions(&typed_value.span), - return err(warnings, errors), - warnings, - errors - ); + type_engine + .get(type_id) + .expect_is_supported_in_match_expressions(handler, &typed_value.span)?; // type check the match expression and create a ty::TyMatchExpression object let (typed_match_expression, typed_scrutinees) = { let ctx = ctx.by_ref().with_help_text(""); - check!( - ty::TyMatchExpression::type_check(ctx, typed_value, branches, span.clone()), - return err(warnings, errors), - warnings, - errors - ) + ty::TyMatchExpression::type_check(handler, ctx, typed_value, branches, span.clone())? }; // check to see if the match expression is exhaustive and if all match arms are reachable - let (witness_report, arms_reachability) = check!( - check_match_expression_usefulness( - engines, - type_id, - typed_scrutinees.clone(), - span.clone() - ), - return err(warnings, errors), - warnings, - errors - ); + let (witness_report, arms_reachability) = check_match_expression_usefulness( + handler, + engines, + type_id, + typed_scrutinees.clone(), + span.clone(), + )?; for reachable_report in arms_reachability.into_iter() { if !reachable_report.reachable { - warnings.push(CompileWarning { + handler.emit_warn(CompileWarning { span: reachable_report.span, warning_content: Warning::MatchExpressionUnreachableArm, }); } } if witness_report.has_witnesses() { - errors.push(CompileError::MatchExpressionNonExhaustive { - missing_patterns: format!("{witness_report}"), - span, - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MatchExpressionNonExhaustive { + missing_patterns: format!("{witness_report}"), + span, + }), + ); } // desugar the typed match expression to a typed if expression - let typed_if_exp = check!( - typed_match_expression.convert_to_typed_if_expression(ctx), - return err(warnings, errors), - warnings, - errors - ); + let typed_if_exp = typed_match_expression.convert_to_typed_if_expression(handler, ctx)?; let match_exp = ty::TyExpression { span: typed_if_exp.span.clone(), @@ -721,18 +686,16 @@ impl ty::TyExpression { }, }; - ok(match_exp, warnings, errors) + Ok(match_exp) } #[allow(clippy::too_many_arguments)] fn type_check_asm_expression( + handler: &Handler, mut ctx: TypeCheckContext, asm: AsmExpression, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -740,29 +703,22 @@ impl ty::TyExpression { // this includes two checks: // 1. Check that no control flow opcodes are used. // 2. Check that initialized registers are not reassigned in the `asm` block. - check!( - check_asm_block_validity(&asm), - return err(warnings, errors), - warnings, - errors - ); + check_asm_block_validity(handler, &asm)?; let asm_span = asm .returns .clone() .map(|x| x.1) .unwrap_or_else(|| asm.whole_block_span.clone()); - let return_type = check!( - ctx.resolve_type_with_self( + let return_type = ctx + .resolve_type_with_self( + handler, type_engine.insert(engines, asm.return_type.clone()), &asm_span, EnforceTypeArguments::No, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); // type check the initializers let typed_registers = @@ -776,12 +732,11 @@ impl ty::TyExpression { let ctx = ctx.by_ref().with_help_text("").with_type_annotation( type_engine.insert(engines, TypeInfo::Unknown), ); - check!( - ty::TyExpression::type_check(ctx, initializer.clone()), - ty::TyExpression::error(initializer.span(), engines), - warnings, - errors - ) + + ty::TyExpression::type_check(handler, ctx, initializer.clone()) + .unwrap_or_else(|_| { + ty::TyExpression::error(initializer.span(), engines) + }) }), }, ) @@ -797,47 +752,33 @@ impl ty::TyExpression { return_type, span, }; - ok(exp, warnings, errors) + Ok(exp) } fn type_check_subfield_expression( + handler: &Handler, ctx: TypeCheckContext, prefix: Expression, span: Span, field_to_access: Ident, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let parent = check!( - ty::TyExpression::type_check(ctx, prefix), - return err(warnings, errors), - warnings, - errors - ); - let exp = check!( - instantiate_struct_field_access(engines, parent, field_to_access, span), - return err(warnings, errors), - warnings, - errors - ); - ok(exp, warnings, errors) + let parent = ty::TyExpression::type_check(handler, ctx, prefix)?; + let exp = instantiate_struct_field_access(handler, engines, parent, field_to_access, span)?; + Ok(exp) } fn type_check_tuple( + handler: &Handler, mut ctx: TypeCheckContext, fields: Vec, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -867,12 +808,8 @@ impl ty::TyExpression { .by_ref() .with_help_text("tuple field type does not match the expected type") .with_type_annotation(field_type.type_id); - let typed_field = check!( - ty::TyExpression::type_check(ctx, field), - ty::TyExpression::error(field_span, engines), - warnings, - errors - ); + let typed_field = ty::TyExpression::type_check(handler, ctx, field) + .unwrap_or_else(|_| ty::TyExpression::error(field_span, engines)); typed_field_types.push(TypeArgument { type_id: typed_field.return_type, initial_type_id: field_type.type_id, @@ -891,49 +828,39 @@ impl ty::TyExpression { .insert(engines, TypeInfo::Tuple(typed_field_types)), span, }; - ok(exp, warnings, errors) + Ok(exp) } /// Look up the current global storage state that has been created by storage declarations. /// If there isn't any storage, then this is an error. If there is storage, find the corresponding /// field that has been specified and return that value. fn type_check_storage_access( + handler: &Handler, ctx: TypeCheckContext, checkee: Vec, storage_keyword_span: Span, span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); if !ctx.namespace.has_storage_declared() { - errors.push(CompileError::NoDeclaredStorage { span: span.clone() }); - return err(warnings, errors); + return Err(handler.emit_err(CompileError::NoDeclaredStorage { span: span.clone() })); } - let storage_fields = check!( - ctx.namespace.get_storage_field_descriptors(decl_engine), - return err(warnings, errors), - warnings, - errors - ); + let storage_fields = ctx + .namespace + .get_storage_field_descriptors(handler, decl_engine)?; // Do all namespace checking here! - let (storage_access, mut access_type) = check!( - ctx.namespace.apply_storage_load( - ctx.engines, - checkee, - &storage_fields, - storage_keyword_span - ), - return err(warnings, errors), - warnings, - errors - ); + let (storage_access, mut access_type) = ctx.namespace.apply_storage_load( + handler, + ctx.engines, + checkee, + &storage_fields, + storage_keyword_span, + )?; // The type of a storage access is `core::storage::StorageKey`. This is // the path to it. @@ -944,20 +871,12 @@ impl ty::TyExpression { let storage_key_ident = Ident::new_with_override("StorageKey".into(), span.clone()); // Search for the struct declaration with the call path above. - let storage_key_decl_opt = check!( - ctx.namespace - .root() - .resolve_symbol(&storage_key_mod_path, &storage_key_ident), - return err(warnings, errors), - warnings, - errors - ); - let storage_key_struct_decl_ref = check!( - storage_key_decl_opt.to_struct_ref(engines), - return err(warnings, errors), - warnings, - errors - ); + let storage_key_decl_opt = ctx.namespace.root().resolve_symbol( + handler, + &storage_key_mod_path, + &storage_key_ident, + )?; + let storage_key_struct_decl_ref = storage_key_decl_opt.to_struct_ref(handler, engines)?; let mut storage_key_struct_decl = decl_engine.get_struct(&storage_key_struct_decl_ref); // Set the type arguments to `StorageKey` to the `access_type`, which is represents the @@ -971,17 +890,13 @@ impl ty::TyExpression { // Monomorphize the generic `StorageKey` type given the type argument specified above let mut ctx = ctx; - check!( - ctx.monomorphize( - &mut storage_key_struct_decl, - &mut type_arguments, - EnforceTypeArguments::Yes, - span - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut storage_key_struct_decl, + &mut type_arguments, + EnforceTypeArguments::Yes, + span, + )?; // Update `access_type` to be the type of the monomorphized struct after inserting it // into the type engine @@ -993,49 +908,35 @@ impl ty::TyExpression { ctx.namespace .insert_trait_implementation_for_type(engines, access_type); - ok( - ty::TyExpression { - expression: ty::TyExpressionVariant::StorageAccess(storage_access), - return_type: access_type, - span: span.clone(), - }, - warnings, - errors, - ) + Ok(ty::TyExpression { + expression: ty::TyExpressionVariant::StorageAccess(storage_access), + return_type: access_type, + span: span.clone(), + }) } fn type_check_tuple_index( + handler: &Handler, ctx: TypeCheckContext, prefix: Expression, index: usize, index_span: Span, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let parent = check!( - ty::TyExpression::type_check(ctx, prefix), - return err(warnings, errors), - warnings, - errors - ); - let exp = check!( - instantiate_tuple_index_access(engines, parent, index, index_span, span), - return err(warnings, errors), - warnings, - errors - ); - ok(exp, warnings, errors) + let parent = ty::TyExpression::type_check(handler, ctx, prefix)?; + let exp = + instantiate_tuple_index_access(handler, engines, parent, index, index_span, span)?; + Ok(exp) } fn type_check_ambiguous_path( + handler: &Handler, mut ctx: TypeCheckContext, TypeBinding { inner: @@ -1050,20 +951,17 @@ impl ty::TyExpression { span: Span, args: Vec, qualified_path_root: Option, - ) -> CompileResult { + ) -> Result { let decl_engine = ctx.engines.de(); if let Some(QualifiedPathRootTypes { ty, as_trait, .. }) = qualified_path_root { if !prefixes.is_empty() || before.is_some() { - return err( - vec![], - vec![ - ConvertParseTreeError::UnexpectedCallPathPrefixAfterQualifiedRoot { - span: path_span, - } - .into(), - ], - ); + return Err(handler.emit_err( + ConvertParseTreeError::UnexpectedCallPathPrefixAfterQualifiedRoot { + span: path_span, + } + .into(), + )); } let method_name_binding = TypeBinding { @@ -1077,6 +975,7 @@ impl ty::TyExpression { }; return type_check_method_application( + handler, ctx.by_ref(), method_name_binding, Vec::new(), @@ -1101,13 +1000,19 @@ impl ty::TyExpression { }; if matches!( ctx.namespace - .resolve_call_path(&call_path_binding.inner) - .value, - Some(ty::TyDecl::EnumVariantDecl { .. }) + .resolve_call_path(&Handler::default(), &call_path_binding.inner), + Ok(ty::TyDecl::EnumVariantDecl { .. }) ) { - return Self::type_check_delineated_path(ctx, call_path_binding, span, Some(args)); + return Self::type_check_delineated_path( + handler, + ctx, + call_path_binding, + span, + Some(args), + ); } else { return Self::type_check_function_application( + handler, ctx.by_ref(), call_path_binding, args, @@ -1120,7 +1025,10 @@ impl ty::TyExpression { let mut path = Vec::with_capacity(prefixes.len() + 1); path.extend(prefixes.iter().cloned()); path.push(before.inner.clone()); - let not_module = ctx.namespace.check_submodule(&path).value.is_none(); + let not_module = { + let h = Handler::default(); + ctx.namespace.check_submodule(&h, &path).is_err() + }; // Not a module? Not a `Enum::Variant` either? // Type check as an associated function call instead. @@ -1131,12 +1039,14 @@ impl ty::TyExpression { is_absolute, }; ctx.namespace - .resolve_call_path(&probe_call_path) - .flat_map(|decl| decl.to_enum_ref(ctx.engines())) + .resolve_call_path(&Handler::default(), &probe_call_path) + .and_then(|decl| decl.to_enum_ref(&Handler::default(), ctx.engines())) .map(|decl_ref| decl_engine.get_enum(&decl_ref)) - .flat_map(|decl| decl.expect_variant_from_name(&suffix).map(drop)) - .value - .is_none() + .and_then(|decl| { + decl.expect_variant_from_name(&Handler::default(), &suffix) + .map(drop) + }) + .is_err() }; if is_associated_call { @@ -1163,18 +1073,22 @@ impl ty::TyExpression { type_arguments, span: path_span, }; - type_check_method_application(ctx.by_ref(), method_name_binding, Vec::new(), args, span) + type_check_method_application( + handler, + ctx.by_ref(), + method_name_binding, + Vec::new(), + args, + span, + ) } else { let mut type_arguments = type_arguments; if let TypeArgs::Regular(vec) = before.type_arguments { if !vec.is_empty() { if !type_arguments.to_vec().is_empty() { - return err( - vec![], - vec![ - ConvertParseTreeError::MultipleGenericsNotSupported { span }.into() - ], - ); + return Err(handler.emit_err( + ConvertParseTreeError::MultipleGenericsNotSupported { span }.into(), + )); } type_arguments = TypeArgs::Prefix(vec) } @@ -1189,54 +1103,54 @@ impl ty::TyExpression { type_arguments, span: path_span, }; - Self::type_check_delineated_path(ctx, call_path_binding, span, Some(args)) + Self::type_check_delineated_path(handler, ctx, call_path_binding, span, Some(args)) } } fn type_check_delineated_path( + handler: &Handler, mut ctx: TypeCheckContext, unknown_call_path_binding: TypeBinding, span: Span, args: Option>, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { // The first step is to determine if the call path refers to a module, // enum, function or constant. // If only one exists, then we use that one. Otherwise, if more than one exist, it is // an ambiguous reference error. // Check if this could be a module - let mut module_probe_warnings = Vec::new(); - let mut module_probe_errors = Vec::new(); + let module_probe_handler = Handler::default(); let is_module = { let call_path_binding = unknown_call_path_binding.clone(); ctx.namespace .check_submodule( + &module_probe_handler, &[ call_path_binding.inner.prefixes, vec![call_path_binding.inner.suffix], ] .concat(), ) - .ok(&mut module_probe_warnings, &mut module_probe_errors) + .ok() .is_some() }; // Check if this could be a function - let mut function_probe_warnings = Vec::new(); - let mut function_probe_errors = Vec::new(); + let function_probe_handler = Handler::default(); let maybe_function: Option<(DeclRefFunction, _)> = { let mut call_path_binding = unknown_call_path_binding.clone(); - TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()) - .ok(&mut function_probe_warnings, &mut function_probe_errors) - .map(|(fn_ref, _, _)| (fn_ref, call_path_binding)) + TypeBinding::type_check( + &mut call_path_binding, + &function_probe_handler, + ctx.by_ref(), + ) + .ok() + .map(|(fn_ref, _, _)| (fn_ref, call_path_binding)) }; // Check if this could be an enum - let mut enum_probe_warnings = vec![]; - let mut enum_probe_errors = vec![]; + let enum_probe_handler = Handler::default(); let maybe_enum: Option<(DeclRefEnum, _, _, _)> = { let call_path_binding = unknown_call_path_binding.clone(); let variant_name = call_path_binding.inner.suffix.clone(); @@ -1247,8 +1161,8 @@ impl ty::TyExpression { type_arguments: call_path_binding.type_arguments, span: call_path_binding.span, }; - TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()) - .ok(&mut enum_probe_warnings, &mut enum_probe_errors) + TypeBinding::type_check(&mut call_path_binding, &enum_probe_handler, ctx.by_ref()) + .ok() .map(|(enum_ref, _, ty_decl)| { ( enum_ref, @@ -1260,16 +1174,9 @@ impl ty::TyExpression { }; // Check if this could be a constant - let mut const_probe_warnings = vec![]; - let mut const_probe_errors = vec![]; - let maybe_const = { - Self::probe_const_decl( - &unknown_call_path_binding, - &mut ctx, - &mut const_probe_warnings, - &mut const_probe_errors, - ) - }; + let const_probe_handler = Handler::default(); + let maybe_const = + { Self::probe_const_decl(&unknown_call_path_binding, &mut ctx, &const_probe_handler) }; // compare the results of the checks let exp = match (is_module, maybe_function, maybe_enum, maybe_const) { @@ -1279,89 +1186,76 @@ impl ty::TyExpression { Some((enum_ref, variant_name, call_path_binding, call_path_decl)), None, ) => { - warnings.append(&mut enum_probe_warnings); - errors.append(&mut enum_probe_errors); - check!( - instantiate_enum( - ctx, - enum_ref, - variant_name, - args, - call_path_binding, - call_path_decl, - &span - ), - return err(warnings, errors), - warnings, - errors - ) + handler.append(enum_probe_handler); + instantiate_enum( + handler, + ctx, + enum_ref, + variant_name, + args, + call_path_binding, + call_path_decl, + &span, + )? } (false, Some((fn_ref, call_path_binding)), None, None) => { - warnings.append(&mut function_probe_warnings); - errors.append(&mut function_probe_errors); + handler.append(function_probe_handler); // In case `foo::bar::::baz(...)` throw an error. if let TypeArgs::Prefix(_) = call_path_binding.type_arguments { - errors.push( + handler.emit_err( ConvertParseTreeError::GenericsNotSupportedHere { span: call_path_binding.type_arguments.span(), } .into(), ); } - check!( - instantiate_function_application(ctx, fn_ref, call_path_binding, args, span), - return err(warnings, errors), - warnings, - errors - ) + instantiate_function_application( + handler, + ctx, + fn_ref, + call_path_binding, + args, + span, + )? } (true, None, None, None) => { - module_probe_errors.push(CompileError::Unimplemented( + handler.append(module_probe_handler); + return Err(handler.emit_err(CompileError::Unimplemented( "this case is not yet implemented", span, - )); - return err(module_probe_warnings, module_probe_errors); + ))); } (false, None, None, Some((const_ref, call_path_binding))) => { - warnings.append(&mut const_probe_warnings); - errors.append(&mut const_probe_errors); + handler.append(const_probe_handler); if !call_path_binding.type_arguments.to_vec().is_empty() { // In case `foo::bar::CONST::` throw an error. // In case `foo::bar::::CONST` throw an error. - errors.push( + handler.emit_err( ConvertParseTreeError::GenericsNotSupportedHere { span: unknown_call_path_binding.type_arguments.span(), } .into(), ); } - check!( - instantiate_constant_expression(ctx, const_ref, call_path_binding), - return err(warnings, errors), - warnings, - errors - ) + instantiate_constant_expression(ctx, const_ref, call_path_binding) } (false, None, None, None) => { - errors.push(CompileError::SymbolNotFound { + return Err(handler.emit_err(CompileError::SymbolNotFound { name: unknown_call_path_binding.inner.suffix.clone(), span: unknown_call_path_binding.inner.suffix.span(), - }); - return err(warnings, errors); + })); } _ => { - errors.push(CompileError::AmbiguousPath { span }); - return err(warnings, errors); + return Err(handler.emit_err(CompileError::AmbiguousPath { span })); } }; - ok(exp, warnings, errors) + Ok(exp) } fn probe_const_decl( unknown_call_path_binding: &TypeBinding, ctx: &mut TypeCheckContext, - const_probe_warnings: &mut Vec, - const_probe_errors: &mut Vec, + const_probe_handler: &Handler, ) -> Option<(DeclRefConstant, TypeBinding)> { let mut call_path_binding = unknown_call_path_binding.clone(); @@ -1382,16 +1276,13 @@ impl ty::TyExpression { } let const_opt: Option<(DeclRefConstant, _)> = - TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()) - .ok(const_probe_warnings, const_probe_errors) + TypeBinding::type_check(&mut call_path_binding, &Handler::default(), ctx.by_ref()) + .ok() .map(|(const_ref, _, _)| (const_ref, call_path_binding.clone())); if const_opt.is_some() { return const_opt; } - *const_probe_warnings = vec![]; - *const_probe_errors = vec![]; - // If we didn't find a constant, check for the constant inside the impl. let suffix = call_path_binding.inner.suffix.clone(); let const_call_path = call_path_binding.inner.rshift(); @@ -1402,38 +1293,37 @@ impl ty::TyExpression { span: call_path_binding.span.clone(), }; - let (_, struct_type_id, _): (DeclRefStruct, _, _) = check!( - TypeBinding::type_check(&mut const_call_path_binding, ctx.by_ref()), - return None, - const_probe_warnings, - const_probe_errors - ); + let (_, struct_type_id, _): (DeclRefStruct, _, _) = match TypeBinding::type_check( + &mut const_call_path_binding, + const_probe_handler, + ctx.by_ref(), + ) { + Ok(val) => val, + Err(_) => return None, + }; - let const_decl_ref = check!( - ctx.namespace.find_constant_for_type( - struct_type_id.unwrap(), - &suffix, - ctx.self_type(), - ctx.engines(), - ), - return None, - const_probe_warnings, - const_probe_errors - ); + let const_decl_ref = match ctx.namespace.find_constant_for_type( + const_probe_handler, + struct_type_id.unwrap(), + &suffix, + ctx.self_type(), + ctx.engines(), + ) { + Ok(val) => val, + Err(_) => return None, + }; Some((const_decl_ref, call_path_binding.clone())) } #[allow(clippy::too_many_arguments)] fn type_check_abi_cast( + handler: &Handler, mut ctx: TypeCheckContext, abi_name: CallPath, address: Expression, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -1446,21 +1336,15 @@ impl ty::TyExpression { .by_ref() .with_help_text("An address that is being ABI cast must be of type b256") .with_type_annotation(type_engine.insert(engines, TypeInfo::B256)); - check!( - ty::TyExpression::type_check(ctx, address), - ty::TyExpression::error(err_span, engines), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, address) + .unwrap_or_else(|_| ty::TyExpression::error(err_span, engines)) }; // look up the call path and get the declaration it references - let abi = check!( - ctx.namespace.resolve_call_path(&abi_name).cloned(), - return err(warnings, errors), - warnings, - errors - ); + let abi = ctx + .namespace + .resolve_call_path(handler, &abi_name) + .cloned()?; let abi_ref = match abi { ty::TyDecl::AbiDecl(ty::AbiDecl { name, @@ -1473,54 +1357,41 @@ impl ty::TyExpression { let abi_name = match ret_ty { TypeInfo::ContractCaller { abi_name, .. } => abi_name, _ => { - errors.push(CompileError::NotAnAbi { + return Err(handler.emit_err(CompileError::NotAnAbi { span: abi_name.span(), actually_is: abi.friendly_type_name(), - }); - return err(warnings, errors); + })); } }; match abi_name { // look up the call path and get the declaration it references AbiName::Known(abi_name) => { - let unknown_decl = check!( - ctx.namespace.resolve_call_path(&abi_name).cloned(), - return err(warnings, errors), - warnings, - errors - ); - check!( - unknown_decl.to_abi_ref(), - return err(warnings, errors), - warnings, - errors - ) + let unknown_decl = ctx + .namespace + .resolve_call_path(handler, &abi_name) + .cloned()?; + unknown_decl.to_abi_ref(handler)? } AbiName::Deferred => { - return ok( - ty::TyExpression { - return_type: type_engine.insert( - engines, - TypeInfo::ContractCaller { - abi_name: AbiName::Deferred, - address: None, - }, - ), - expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, - span, - }, - warnings, - errors, - ) + return Ok(ty::TyExpression { + return_type: type_engine.insert( + engines, + TypeInfo::ContractCaller { + abi_name: AbiName::Deferred, + address: None, + }, + ), + expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, + span, + }) } } } a => { - errors.push(CompileError::NotAnAbi { + return Err(handler.emit_err(CompileError::NotAnAbi { span: abi_name.span(), actually_is: a.friendly_type_name(), - }); - return err(warnings, errors); + })); } }; let ty::TyAbiDecl { @@ -1567,34 +1438,26 @@ impl ty::TyExpression { // Recursively make the interface surfaces and methods of the // supertraits available to this abi cast. - check!( - insert_supertraits_into_namespace( - ctx.by_ref(), - return_type, - &supertraits, - &SupertraitOf::Abi(span.clone()) - ), - return err(warnings, errors), - warnings, - errors - ); + insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + return_type, + &supertraits, + &SupertraitOf::Abi(span.clone()), + )?; // Insert the abi methods into the namespace. - check!( - ctx.namespace.insert_trait_implementation( - abi_name.clone(), - vec![], - return_type, - &abi_items, - &span, - Some(span.clone()), - false, - engines, - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace.insert_trait_implementation( + handler, + abi_name.clone(), + vec![], + return_type, + &abi_items, + &span, + Some(span.clone()), + false, + engines, + )?; let exp = ty::TyExpression { expression: ty::TyExpressionVariant::AbiCast { @@ -1605,46 +1468,41 @@ impl ty::TyExpression { return_type, span, }; - ok(exp, warnings, errors) + Ok(exp) } fn type_check_array( + handler: &Handler, mut ctx: TypeCheckContext, contents: Vec, span: Span, - ) -> CompileResult { + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); if contents.is_empty() { let unknown_type = type_engine.insert(engines, TypeInfo::Unknown); - return ok( - ty::TyExpression { - expression: ty::TyExpressionVariant::Array { - elem_type: unknown_type, - contents: Vec::new(), - }, - return_type: type_engine.insert( - engines, - TypeInfo::Array( - TypeArgument { - type_id: unknown_type, - span: Span::dummy(), - call_path_tree: None, - initial_type_id: unknown_type, - }, - Length::new(0, Span::dummy()), - ), - ), - span, + return Ok(ty::TyExpression { + expression: ty::TyExpressionVariant::Array { + elem_type: unknown_type, + contents: Vec::new(), }, - Vec::new(), - Vec::new(), - ); + return_type: type_engine.insert( + engines, + TypeInfo::Array( + TypeArgument { + type_id: unknown_type, + span: Span::dummy(), + call_path_tree: None, + initial_type_id: unknown_type, + }, + Length::new(0, Span::dummy()), + ), + ), + span, + }); }; - let mut warnings = Vec::new(); - let mut errors = Vec::new(); let typed_contents: Vec = contents .into_iter() .map(|expr| { @@ -1653,25 +1511,25 @@ impl ty::TyExpression { .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - check!( - Self::type_check(ctx, expr), - ty::TyExpression::error(span, engines), - warnings, - errors - ) + Self::type_check(handler, ctx, expr) + .unwrap_or_else(|_| ty::TyExpression::error(span, engines)) }) .collect(); let elem_type = typed_contents[0].return_type; for typed_elem in &typed_contents[1..] { - let (mut new_warnings, mut new_errors) = ctx + let (new_warnings, new_errors) = ctx .by_ref() .with_type_annotation(elem_type) .unify_with_self(typed_elem.return_type, &typed_elem.span); let no_warnings = new_warnings.is_empty(); let no_errors = new_errors.is_empty(); - warnings.append(&mut new_warnings); - errors.append(&mut new_errors); + for warn in new_warnings { + handler.emit_warn(warn); + } + for err in new_errors { + handler.emit_err(err); + } // In both cases, if there are warnings or errors then break here, since we don't // need to spam type errors for every element once we have one. if !no_warnings && !no_errors { @@ -1680,40 +1538,34 @@ impl ty::TyExpression { } let array_count = typed_contents.len(); - ok( - ty::TyExpression { - expression: ty::TyExpressionVariant::Array { - elem_type, - contents: typed_contents, - }, - return_type: type_engine.insert( - engines, - TypeInfo::Array( - TypeArgument { - type_id: elem_type, - span: Span::dummy(), - call_path_tree: None, - initial_type_id: elem_type, - }, - Length::new(array_count, Span::dummy()), - ), - ), // Maybe? - span, + Ok(ty::TyExpression { + expression: ty::TyExpressionVariant::Array { + elem_type, + contents: typed_contents, }, - warnings, - errors, - ) + return_type: type_engine.insert( + engines, + TypeInfo::Array( + TypeArgument { + type_id: elem_type, + span: Span::dummy(), + call_path_tree: None, + initial_type_id: elem_type, + }, + Length::new(array_count, Span::dummy()), + ), + ), // Maybe? + span, + }) } fn type_check_array_index( + handler: &Handler, mut ctx: TypeCheckContext, prefix: Expression, index: Expression, span: Span, - ) -> CompileResult { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -1722,12 +1574,7 @@ impl ty::TyExpression { .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - check!( - ty::TyExpression::type_check(ctx, prefix.clone()), - return err(warnings, errors), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, prefix.clone())? }; fn get_array_type(ty: TypeId, type_engine: &TypeEngine) -> Option { @@ -1746,25 +1593,16 @@ impl ty::TyExpression { let ctx = ctx .with_help_text("") .with_type_annotation(type_engine.insert(engines, type_info_u64)); - let index_te = check!( - ty::TyExpression::type_check(ctx, index), - return err(warnings, errors), - warnings, - errors - ); + let index_te = ty::TyExpression::type_check(handler, ctx, index)?; - ok( - ty::TyExpression { - expression: ty::TyExpressionVariant::ArrayIndex { - prefix: Box::new(prefix_te), - index: Box::new(index_te), - }, - return_type: elem_type.type_id, - span, + Ok(ty::TyExpression { + expression: ty::TyExpressionVariant::ArrayIndex { + prefix: Box::new(prefix_te), + index: Box::new(index_te), }, - warnings, - errors, - ) + return_type: elem_type.type_id, + span, + }) } else { // Otherwise convert into a method call 'index(self, index)' via the std::ops::Index trait. let method_name = TypeBinding { @@ -1781,41 +1619,46 @@ impl ty::TyExpression { type_arguments: TypeArgs::Regular(vec![]), span: span.clone(), }; - type_check_method_application(ctx, method_name, vec![], vec![prefix, index], span) + type_check_method_application( + handler, + ctx, + method_name, + vec![], + vec![prefix, index], + span, + ) } } fn type_check_intrinsic_function( + handler: &Handler, ctx: TypeCheckContext, kind_binding: TypeBinding, arguments: Vec, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - let (intrinsic_function, return_type) = check!( - ty::TyIntrinsicFunctionKind::type_check(ctx, kind_binding, arguments, span.clone()), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result { + let (intrinsic_function, return_type) = ty::TyIntrinsicFunctionKind::type_check( + handler, + ctx, + kind_binding, + arguments, + span.clone(), + )?; let exp = ty::TyExpression { expression: ty::TyExpressionVariant::IntrinsicFunction(intrinsic_function), return_type, span, }; - ok(exp, warnings, errors) + Ok(exp) } fn type_check_while_loop( + handler: &Handler, mut ctx: TypeCheckContext, condition: Expression, body: CodeBlock, span: Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -1824,12 +1667,7 @@ impl ty::TyExpression { .by_ref() .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean)) .with_help_text("A while loop's loop condition must be a boolean expression."); - check!( - ty::TyExpression::type_check(ctx, condition), - return err(warnings, errors), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, condition)? }; let unit_ty = type_engine.insert(engines, TypeInfo::Tuple(Vec::new())); @@ -1838,12 +1676,7 @@ impl ty::TyExpression { assigning it to a mutable variable declared outside of the loop \ instead.", ); - let (typed_body, _block_implicit_return) = check!( - ty::TyCodeBlock::type_check(ctx, body), - return err(warnings, errors), - warnings, - errors - ); + let (typed_body, _block_implicit_return) = ty::TyCodeBlock::type_check(handler, ctx, body)?; let exp = ty::TyExpression { expression: ty::TyExpressionVariant::WhileLoop { condition: Box::new(typed_condition), @@ -1852,18 +1685,16 @@ impl ty::TyExpression { return_type: unit_ty, span, }; - ok(exp, warnings, errors) + Ok(exp) } fn type_check_reassignment( + handler: &Handler, ctx: TypeCheckContext, lhs: ReassignmentTarget, rhs: Expression, span: Span, - ) -> CompileResult { - let mut errors = vec![]; - let mut warnings = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -1879,21 +1710,13 @@ impl ty::TyExpression { match expr.kind { ExpressionKind::Variable(name) => { // check that the reassigned name exists - let unknown_decl = check!( - ctx.namespace.resolve_symbol(&name).cloned(), - return err(warnings, errors), - warnings, - errors - ); - let variable_decl = check!( - unknown_decl.expect_variable().cloned(), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = + ctx.namespace.resolve_symbol(handler, &name).cloned()?; + let variable_decl = unknown_decl.expect_variable(handler).cloned()?; if !variable_decl.mutability.is_mutable() { - errors.push(CompileError::AssignmentToNonMutable { name, span }); - return err(warnings, errors); + return Err(handler.emit_err( + CompileError::AssignmentToNonMutable { name, span }, + )); } break (name, variable_decl.body.return_type); } @@ -1918,12 +1741,11 @@ impl ty::TyExpression { } ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { let ctx = ctx.by_ref().with_help_text(""); - let typed_index = check!( - ty::TyExpression::type_check(ctx, index.as_ref().clone()), - ty::TyExpression::error(span.clone(), engines), - warnings, - errors - ); + let typed_index = + ty::TyExpression::type_check(handler, ctx, index.as_ref().clone()) + .unwrap_or_else(|_| { + ty::TyExpression::error(span.clone(), engines) + }); names_vec.push(ty::ProjectionKind::ArrayIndex { index: Box::new(typed_index), index_span: index.span(), @@ -1931,57 +1753,48 @@ impl ty::TyExpression { expr = prefix; } _ => { - errors.push(CompileError::InvalidExpressionOnLhs { span }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::InvalidExpressionOnLhs { span }) + ); } } }; let names_vec = names_vec.into_iter().rev().collect::>(); - let (ty_of_field, _ty_of_parent) = check!( - ctx.namespace - .find_subfield_type(ctx.engines(), &base_name, &names_vec), - return err(warnings, errors), - warnings, - errors - ); + let (ty_of_field, _ty_of_parent) = ctx.namespace.find_subfield_type( + handler, + ctx.engines(), + &base_name, + &names_vec, + )?; // type check the reassignment let ctx = ctx.with_type_annotation(ty_of_field).with_help_text(""); let rhs_span = rhs.span(); - let rhs = check!( - ty::TyExpression::type_check(ctx, rhs), - ty::TyExpression::error(rhs_span, engines), - warnings, - errors - ); - - ok( - ty::TyExpression { - expression: ty::TyExpressionVariant::Reassignment(Box::new( - ty::TyReassignment { - lhs_base_name: base_name, - lhs_type: final_return_type, - lhs_indices: names_vec, - rhs, - }, - )), - return_type: type_engine.insert(engines, TypeInfo::Tuple(Vec::new())), - span, - }, - warnings, - errors, - ) + let rhs = ty::TyExpression::type_check(handler, ctx, rhs) + .unwrap_or_else(|_| ty::TyExpression::error(rhs_span, engines)); + + Ok(ty::TyExpression { + expression: ty::TyExpressionVariant::Reassignment(Box::new( + ty::TyReassignment { + lhs_base_name: base_name, + lhs_type: final_return_type, + lhs_indices: names_vec, + rhs, + }, + )), + return_type: type_engine.insert(engines, TypeInfo::Tuple(Vec::new())), + span, + }) } } } fn resolve_numeric_literal( + handler: &Handler, ctx: TypeCheckContext, lit: Literal, span: Span, new_type: TypeId, - ) -> CompileResult { - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -2052,12 +1865,12 @@ impl ty::TyExpression { return_type: new_integer_type, span, }; - ok(exp, vec![], vec![]) + Ok(exp) } Err(e) => { - errors.push(e); + handler.emit_err(e); let exp = ty::TyExpression::error(span, engines); - ok(exp, vec![], errors) + Ok(exp) } } } @@ -2070,19 +1883,24 @@ mod tests { use sway_error::type_error::TypeError; fn do_type_check( + handler: &Handler, engines: &Engines, expr: Expression, type_annotation: TypeId, - ) -> CompileResult { + ) -> Result { let mut namespace = Namespace::init_root(namespace::Module::default()); let ctx = TypeCheckContext::from_root(&mut namespace, engines) .with_type_annotation(type_annotation); - ty::TyExpression::type_check(ctx, expr) + ty::TyExpression::type_check(handler, ctx, expr) } - fn do_type_check_for_boolx2(expr: Expression) -> CompileResult { + fn do_type_check_for_boolx2( + handler: &Handler, + expr: Expression, + ) -> Result { let engines = Engines::default(); do_type_check( + handler, &engines, expr, engines.te().insert( @@ -2120,9 +1938,11 @@ mod tests { span: Span::dummy(), }; - let comp_res = do_type_check_for_boolx2(expr); - assert!(comp_res.errors.len() == 1); - assert!(matches!(&comp_res.errors[0], + let handler = Handler::default(); + let _comp_res = do_type_check_for_boolx2(&handler, expr); + let (errors, _warnings) = handler.consume(); + assert!(errors.len() == 1); + assert!(matches!(&errors[0], CompileError::TypeError(TypeError::MismatchedType { expected, received, @@ -2151,16 +1971,18 @@ mod tests { span: Span::dummy(), }; - let comp_res = do_type_check_for_boolx2(expr); - assert!(comp_res.errors.len() == 2); - assert!(matches!(&comp_res.errors[0], + let handler = Handler::default(); + let _comp_res = do_type_check_for_boolx2(&handler, expr); + let (errors, _warnings) = handler.consume(); + assert!(errors.len() == 2); + assert!(matches!(&errors[0], CompileError::TypeError(TypeError::MismatchedType { expected, received, .. }) if expected == "u64" && received == "bool")); - assert!(matches!(&comp_res.errors[1], + assert!(matches!(&errors[1], CompileError::TypeError(TypeError::MismatchedType { expected, received, @@ -2193,9 +2015,11 @@ mod tests { span: Span::dummy(), }; - let comp_res = do_type_check_for_boolx2(expr); - assert!(comp_res.errors.len() == 1); - assert!(matches!(&comp_res.errors[0], + let handler = Handler::default(); + let _comp_res = do_type_check_for_boolx2(&handler, expr); + let (errors, _warnings) = handler.consume(); + assert!(errors.len() == 1); + assert!(matches!(&errors[0], CompileError::TypeError(TypeError::MismatchedType { expected, received, @@ -2215,7 +2039,9 @@ mod tests { }; let engines = Engines::default(); + let handler = Handler::default(); let comp_res = do_type_check( + &handler, &engines, expr, engines.te().insert( @@ -2231,14 +2057,13 @@ mod tests { ), ), ); - assert!(comp_res.warnings.is_empty() && comp_res.errors.is_empty()); + let (errors, warnings) = handler.consume(); + assert!(comp_res.is_ok()); + assert!(warnings.is_empty() && errors.is_empty()); } } -fn check_asm_block_validity(asm: &AsmExpression) -> CompileResult<()> { - let mut errors = vec![]; - let mut warnings = vec![]; - +fn check_asm_block_validity(handler: &Handler, asm: &AsmExpression) -> Result<(), ErrorEmitted> { // Collect all asm block instructions in the form of `VirtualOp`s let mut opcodes = vec![]; for op in &asm.body { @@ -2249,17 +2074,13 @@ fn check_asm_block_validity(asm: &AsmExpression) -> CompileResult<()> { .collect::>(); opcodes.push(( - check!( - crate::asm_lang::Op::parse_opcode( - &op.op_name, - ®isters, - &op.immediate, - op.span.clone(), - ), - return err(warnings, errors), - warnings, - errors - ), + crate::asm_lang::Op::parse_opcode( + handler, + &op.op_name, + ®isters, + &op.immediate, + op.span.clone(), + )?, op.op_name.clone(), op.span.clone(), )); @@ -2267,28 +2088,28 @@ fn check_asm_block_validity(asm: &AsmExpression) -> CompileResult<()> { // Check #1: Disallow control flow instructions // - errors.extend( - opcodes - .iter() - .filter(|op| { - matches!( - op.0, - VirtualOp::JMP(_) - | VirtualOp::JI(_) - | VirtualOp::JNE(..) - | VirtualOp::JNEI(..) - | VirtualOp::JNZI(..) - | VirtualOp::RET(_) - | VirtualOp::RETD(..) - | VirtualOp::RVRT(..) - ) - }) - .map(|op| CompileError::DisallowedControlFlowInstruction { - name: op.1.to_string(), - span: op.2.clone(), - }) - .collect::>(), - ); + for err in opcodes + .iter() + .filter(|op| { + matches!( + op.0, + VirtualOp::JMP(_) + | VirtualOp::JI(_) + | VirtualOp::JNE(..) + | VirtualOp::JNEI(..) + | VirtualOp::JNZI(..) + | VirtualOp::RET(_) + | VirtualOp::RETD(..) + | VirtualOp::RVRT(..) + ) + }) + .map(|op| CompileError::DisallowedControlFlowInstruction { + name: op.1.to_string(), + span: op.2.clone(), + }) + { + handler.emit_err(err); + } // Check #2: Disallow initialized registers from being reassigned in the asm block // @@ -2316,19 +2137,20 @@ fn check_asm_block_validity(asm: &AsmExpression) -> CompileResult<()> { // 4. Form all the compile errors given the violating registers above. Obtain span information // from the original `asm.registers` vector. - errors.extend( - asm.registers - .iter() - .filter(|reg| { - initialized_and_assigned_registers - .contains(&VirtualRegister::Virtual(reg.name.to_string())) - }) - .map(|reg| CompileError::InitializedRegisterReassignment { - name: reg.name.to_string(), - span: reg.name.span(), - }) - .collect::>(), - ); + for err in asm + .registers + .iter() + .filter(|reg| { + initialized_and_assigned_registers + .contains(&VirtualRegister::Virtual(reg.name.to_string())) + }) + .map(|reg| CompileError::InitializedRegisterReassignment { + name: reg.name.to_string(), + span: reg.name.span(), + }) + { + handler.emit_err(err); + } - ok((), vec![], errors) + Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/constant_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/constant_expression.rs index 6bcd6c5bc0e..92b0bf12255 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/constant_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/constant_expression.rs @@ -2,29 +2,24 @@ use sway_types::Spanned; use crate::{ decl_engine::DeclRefConstant, - error::*, language::{ty, CallPath}, semantic_analysis::TypeCheckContext, - CompileResult, TypeBinding, + TypeBinding, }; pub(crate) fn instantiate_constant_expression( ctx: TypeCheckContext, const_ref: DeclRefConstant, call_path_binding: TypeBinding, -) -> CompileResult { +) -> ty::TyExpression { let const_decl = ctx.engines.de().get_constant(const_ref.id()); - ok( - ty::TyExpression { - return_type: const_decl.return_type, - span: call_path_binding.span(), - expression: ty::TyExpressionVariant::ConstantExpression { - const_decl: Box::new(const_decl), - span: call_path_binding.inner.suffix.span(), - call_path: Some(call_path_binding.inner.to_fullpath(ctx.namespace)), - }, + ty::TyExpression { + return_type: const_decl.return_type, + span: call_path_binding.span(), + expression: ty::TyExpressionVariant::ConstantExpression { + const_decl: Box::new(const_decl), + span: call_path_binding.inner.suffix.span(), + call_path: Some(call_path_binding.inner.to_fullpath(ctx.namespace)), }, - vec![], - vec![], - ) + } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs index ff928279bc7..61902a7b5e2 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs @@ -1,18 +1,21 @@ use crate::{ decl_engine::DeclRefEnum, - error::*, language::{parsed::*, ty, CallPath}, semantic_analysis::*, type_system::*, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span, Spanned}; /// Given an enum declaration and the instantiation expression/type arguments, construct a valid /// [ty::TyExpression]. #[allow(clippy::too_many_arguments)] pub(crate) fn instantiate_enum( + handler: &Handler, mut ctx: TypeCheckContext, enum_ref: DeclRefEnum, enum_variant_name: Ident, @@ -20,23 +23,15 @@ pub(crate) fn instantiate_enum( call_path_binding: TypeBinding, call_path_decl: ty::TyDecl, span: &Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); let enum_decl = decl_engine.get_enum(&enum_ref); - let enum_variant = check!( - enum_decl - .expect_variant_from_name(&enum_variant_name) - .cloned(), - return err(warnings, errors), - warnings, - errors - ); + let enum_variant = enum_decl + .expect_variant_from_name(handler, &enum_variant_name) + .cloned()?; // Return an error if enum variant is of type unit and it is called with parenthesis. // args_opt.is_some() returns true when this variant was called with parenthesis. @@ -45,11 +40,12 @@ pub(crate) fn instantiate_enum( .is_unit() && args_opt.is_some() { - errors.push(CompileError::UnitVariantWithParenthesesEnumInstantiator { - span: enum_variant_name.span(), - ty: enum_variant.name.as_str().to_string(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::UnitVariantWithParenthesesEnumInstantiator { + span: enum_variant_name.span(), + ty: enum_variant.name.as_str().to_string(), + }), + ); } let args = args_opt.unwrap_or_default(); @@ -60,98 +56,85 @@ pub(crate) fn instantiate_enum( &args[..], type_engine.get(enum_variant.type_argument.type_id), ) { - ([], ty) if ty.is_unit() => ok( - ty::TyExpression { - return_type: type_engine.insert(engines, TypeInfo::Enum(enum_ref.clone())), - expression: ty::TyExpressionVariant::EnumInstantiation { - tag: enum_variant.tag, - contents: None, - enum_ref, - variant_name: enum_variant.name, - variant_instantiation_span: enum_variant_name.span(), - call_path_binding, - call_path_decl, - }, - span: enum_variant_name.span(), + ([], ty) if ty.is_unit() => Ok(ty::TyExpression { + return_type: type_engine.insert(engines, TypeInfo::Enum(enum_ref.clone())), + expression: ty::TyExpressionVariant::EnumInstantiation { + tag: enum_variant.tag, + contents: None, + enum_ref, + variant_name: enum_variant.name, + variant_instantiation_span: enum_variant_name.span(), + call_path_binding, + call_path_decl, }, - warnings, - errors, - ), + span: enum_variant_name.span(), + }), ([single_expr], _) => { let enum_ctx = ctx .by_ref() .with_help_text("Enum instantiator must match its declared variant type.") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let typed_expr = check!( - ty::TyExpression::type_check(enum_ctx, single_expr.clone()), - return err(warnings, errors), - warnings, - errors - ); + let typed_expr = ty::TyExpression::type_check(handler, enum_ctx, single_expr.clone())?; // unify the value of the argument with the variant - check!( - CompileResult::from(type_engine.unify( - engines, - typed_expr.return_type, - enum_variant.type_argument.type_id, - span, - "Enum instantiator must match its declared variant type.", - None - )), - return err(warnings, errors), - warnings, - errors + let mut error_emitted = None; + let (warnings, errors) = type_engine.unify( + engines, + typed_expr.return_type, + enum_variant.type_argument.type_id, + span, + "Enum instantiator must match its declared variant type.", + None, ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + error_emitted = Some(handler.emit_err(err)); + } + if let Some(err) = error_emitted { + return Err(err); + } // we now know that the instantiator type matches the declared type, via the above tpe // check let type_id = type_engine.insert(engines, TypeInfo::Enum(enum_ref.clone())); - check!( - type_id.check_type_parameter_bounds(&ctx, &enum_variant_name.span(), vec![]), - return err(warnings, errors), - warnings, - errors - ); + type_id.check_type_parameter_bounds( + handler, + &ctx, + &enum_variant_name.span(), + vec![], + )?; - ok( - ty::TyExpression { - return_type: type_id, - expression: ty::TyExpressionVariant::EnumInstantiation { - tag: enum_variant.tag, - contents: Some(Box::new(typed_expr)), - enum_ref, - variant_name: enum_variant.name, - variant_instantiation_span: enum_variant_name.span(), - call_path_binding, - call_path_decl, - }, - span: enum_variant_name.span(), + Ok(ty::TyExpression { + return_type: type_id, + expression: ty::TyExpressionVariant::EnumInstantiation { + tag: enum_variant.tag, + contents: Some(Box::new(typed_expr)), + enum_ref, + variant_name: enum_variant.name, + variant_instantiation_span: enum_variant_name.span(), + call_path_binding, + call_path_decl, }, - warnings, - errors, - ) - } - ([], _) => { - errors.push(CompileError::MissingEnumInstantiator { span: enum_variant_name.span(), - }); - err(warnings, errors) + }) } + ([], _) => Err(handler.emit_err(CompileError::MissingEnumInstantiator { + span: enum_variant_name.span(), + })), (_too_many_expressions, ty) if ty.is_unit() => { - errors.push(CompileError::UnnecessaryEnumInstantiator { + Err(handler.emit_err(CompileError::UnnecessaryEnumInstantiator { span: enum_variant_name.span(), - }); - err(warnings, errors) + })) } (_too_many_expressions, ty) => { - errors.push(CompileError::MoreThanOneEnumInstantiator { + Err(handler.emit_err(CompileError::MoreThanOneEnumInstantiator { span: enum_variant_name.span(), ty: engines.help_out(ty).to_string(), - }); - err(warnings, errors) + })) } } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs index 173c73b7eaf..f9db8859f90 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs @@ -1,6 +1,5 @@ use crate::{ decl_engine::{DeclEngineInsert, DeclRefFunction, ReplaceDecls}, - error::*, language::{ty, *}, semantic_analysis::{ast_node::*, TypeCheckContext}, }; @@ -10,63 +9,53 @@ use sway_types::Spanned; #[allow(clippy::too_many_arguments)] pub(crate) fn instantiate_function_application( + handler: &Handler, mut ctx: TypeCheckContext, function_decl_ref: DeclRefFunction, call_path_binding: TypeBinding, arguments: Option>, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); let mut function_decl = decl_engine.get_function(&function_decl_ref); if arguments.is_none() { - errors.push(CompileError::MissingParenthesesForFunction { - method_name: call_path_binding.inner.suffix.clone(), - span: call_path_binding.inner.span(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::MissingParenthesesForFunction { + method_name: call_path_binding.inner.suffix.clone(), + span: call_path_binding.inner.span(), + }), + ); } let arguments = arguments.unwrap_or_default(); // 'purity' is that of the callee, 'opts.purity' of the caller. if !ctx.purity().can_call(function_decl.purity) { - errors.push(CompileError::StorageAccessMismatch { + handler.emit_err(CompileError::StorageAccessMismatch { attrs: promote_purity(ctx.purity(), function_decl.purity).to_attribute_syntax(), span: call_path_binding.span(), }); } // check that the number of parameters and the number of the arguments is the same - check!( - check_function_arguments_arity( - arguments.len(), - &function_decl, - &call_path_binding.inner, - false - ), - return err(warnings, errors), - warnings, - errors - ); - - let typed_arguments = check!( - type_check_arguments(ctx.by_ref(), arguments), - return err(warnings, errors), - warnings, - errors - ); - - let typed_arguments_with_names = check!( - unify_arguments_and_parameters(ctx.by_ref(), typed_arguments, &function_decl.parameters), - return err(warnings, errors), - warnings, - errors - ); + check_function_arguments_arity( + handler, + arguments.len(), + &function_decl, + &call_path_binding.inner, + false, + )?; + + let typed_arguments = type_check_arguments(handler, ctx.by_ref(), arguments)?; + + let typed_arguments_with_names = unify_arguments_and_parameters( + handler, + ctx.by_ref(), + typed_arguments, + &function_decl.parameters, + )?; // Retrieve the implemented traits for the type of the return type and // insert them in the broader namespace. @@ -76,16 +65,12 @@ pub(crate) fn instantiate_function_application( // Handle the trait constraints. This includes checking to see if the trait // constraints are satisfied and replacing old decl ids based on the // constraint with new decl ids based on the new type. - let decl_mapping = check!( - TypeParameter::gather_decl_mapping_from_trait_constraints( - ctx.by_ref(), - &function_decl.type_parameters, - &call_path_binding.span() - ), - return err(warnings, errors), - warnings, - errors - ); + let decl_mapping = TypeParameter::gather_decl_mapping_from_trait_constraints( + handler, + ctx.by_ref(), + &function_decl.type_parameters, + &call_path_binding.span(), + )?; function_decl.replace_decls(&decl_mapping, engines); let return_type = function_decl.return_type.clone(); let new_decl_ref = decl_engine @@ -106,20 +91,20 @@ pub(crate) fn instantiate_function_application( span, }; - ok(exp, warnings, errors) + Ok(exp) } /// Type checks the arguments. fn type_check_arguments( + handler: &Handler, mut ctx: TypeCheckContext, arguments: Vec, -) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result, ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); + let mut error_emitted = None; + let typed_arguments = arguments .into_iter() .map(|arg| { @@ -127,81 +112,85 @@ fn type_check_arguments( .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - check!( - ty::TyExpression::type_check(ctx, arg.clone()), - ty::TyExpression::error(arg.span(), engines), - warnings, - errors - ) + ty::TyExpression::type_check(handler, ctx, arg.clone()).unwrap_or_else(|err| { + error_emitted = Some(err); + ty::TyExpression::error(arg.span(), engines) + }) }) .collect(); - if errors.is_empty() { - ok(typed_arguments, warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(typed_arguments) } } /// Unifies the types of the arguments with the types of the parameters. Returns /// a list of the arguments with the names of the corresponding parameters. fn unify_arguments_and_parameters( + handler: &Handler, ctx: TypeCheckContext, typed_arguments: Vec, parameters: &[ty::TyFunctionParameter], -) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result, ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let mut typed_arguments_and_names = vec![]; + let mut error_emitted = None; + for (arg, param) in typed_arguments.into_iter().zip(parameters.iter()) { // unify the type of the argument with the type of the param - check!( - CompileResult::from(type_engine.unify( - engines, - arg.return_type, - param.type_argument.type_id, - &arg.span, - "The argument that has been provided to this function's type does \ + + let (warnings, errors) = type_engine.unify( + engines, + arg.return_type, + param.type_argument.type_id, + &arg.span, + "The argument that has been provided to this function's type does \ not match the declared type of the parameter in the function \ declaration.", - None - )), - continue, - warnings, - errors + None, ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors.clone() { + error_emitted = Some(handler.emit_err(err)); + } + if !errors.is_empty() { + continue; + } // check for matching mutability let param_mutability = ty::VariableMutability::new_from_ref_mut(param.is_reference, param.is_mutable); if arg.gather_mutability().is_immutable() && param_mutability.is_mutable() { - errors.push(CompileError::ImmutableArgumentToMutableParameter { - span: arg.span.clone(), - }); + error_emitted = Some(handler.emit_err( + CompileError::ImmutableArgumentToMutableParameter { + span: arg.span.clone(), + }, + )); } typed_arguments_and_names.push((param.name.clone(), arg)); } - if errors.is_empty() { - ok(typed_arguments_and_names, warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(typed_arguments_and_names) } } pub(crate) fn check_function_arguments_arity( + handler: &Handler, arguments_len: usize, function_decl: &ty::TyFunctionDecl, call_path: &CallPath, is_method_call_syntax_used: bool, -) -> CompileResult<()> { - let warnings = vec![]; - let mut errors = vec![]; +) -> Result<(), ErrorEmitted> { // if is_method_call_syntax_used then we have the guarantee // that at least the self argument is passed let (expected, received) = if is_method_call_syntax_used { @@ -210,26 +199,24 @@ pub(crate) fn check_function_arguments_arity( (function_decl.parameters.len(), arguments_len) }; match expected.cmp(&received) { - std::cmp::Ordering::Equal => ok((), warnings, errors), + std::cmp::Ordering::Equal => Ok(()), std::cmp::Ordering::Less => { - errors.push(CompileError::TooFewArgumentsForFunction { + Err(handler.emit_err(CompileError::TooFewArgumentsForFunction { span: call_path.span(), method_name: function_decl.name.clone(), dot_syntax_used: is_method_call_syntax_used, expected, received, - }); - err(warnings, errors) + })) } std::cmp::Ordering::Greater => { - errors.push(CompileError::TooManyArgumentsForFunction { + Err(handler.emit_err(CompileError::TooManyArgumentsForFunction { span: call_path.span(), method_name: function_decl.name.clone(), dot_syntax_used: is_method_call_syntax_used, expected, received, - }); - err(warnings, errors) + })) } } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs index 0c5a88f552c..a6ddc826a5b 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs @@ -1,21 +1,22 @@ -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::Span; use crate::{ - error::*, language::ty, semantic_analysis::TypeCheckContext, type_system::*, + language::ty, semantic_analysis::TypeCheckContext, type_system::*, types::DeterministicallyAborts, }; pub(crate) fn instantiate_if_expression( + handler: &Handler, ctx: TypeCheckContext, condition: ty::TyExpression, then: ty::TyExpression, r#else: Option, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -29,19 +30,21 @@ pub(crate) fn instantiate_if_expression( } else { type_engine.insert(engines, TypeInfo::Tuple(vec![])) }; - append!( - type_engine.unify_with_self( - engines, - then.return_type, - ty_to_check, - ctx.self_type(), - &then.span, - "`then` branch must return expected type.", - None - ), - warnings, - errors + let (warnings, errors) = type_engine.unify_with_self( + engines, + then.return_type, + ty_to_check, + ctx.self_type(), + &then.span, + "`then` branch must return expected type.", + None, ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } } let mut else_deterministically_aborts = false; let r#else = r#else.map(|r#else| { @@ -53,19 +56,21 @@ pub(crate) fn instantiate_if_expression( }; if !else_deterministically_aborts { // if this does not deterministically_abort, check the block return type - append!( - type_engine.unify_with_self( - engines, - r#else.return_type, - ty_to_check, - ctx.self_type(), - &r#else.span, - "`else` branch must return expected type.", - None - ), - warnings, - errors + let (warnings, errors) = type_engine.unify_with_self( + engines, + r#else.return_type, + ty_to_check, + ctx.self_type(), + &r#else.span, + "`else` branch must return expected type.", + None, ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } } Box::new(r#else) }); @@ -76,7 +81,7 @@ pub(crate) fn instantiate_if_expression( .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Tuple(Vec::new()))); // if there is a type annotation, then the else branch must exist if !else_deterministically_aborts && !then_deterministically_aborts { - let (mut new_warnings, mut new_errors) = type_engine.unify_with_self( + let (new_warnings, new_errors) = type_engine.unify_with_self( engines, then.return_type, r#else_ret_ty, @@ -85,16 +90,20 @@ pub(crate) fn instantiate_if_expression( "The two branches of an if expression must return the same type.", None, ); - warnings.append(&mut new_warnings); + for warn in new_warnings { + handler.emit_warn(warn); + } if new_errors.is_empty() { if !type_engine.get(r#else_ret_ty).is_unit() && r#else.is_none() { - errors.push(CompileError::NoElseBranch { + handler.emit_err(CompileError::NoElseBranch { span: span.clone(), r#type: engines.help_out(ctx.type_annotation()).to_string(), }); } } else { - errors.append(&mut new_errors); + for err in new_errors { + handler.emit_err(err); + } } } @@ -112,5 +121,5 @@ pub(crate) fn instantiate_if_expression( return_type, span, }; - ok(exp, warnings, errors) + Ok(exp) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index 3c3d17586a6..9de45a3f5ba 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -1,28 +1,28 @@ use crate::{ decl_engine::{DeclEngineInsert, DeclRefFunction, ReplaceDecls, UpdateConstantExpression}, - error::*, language::{parsed::*, ty, *}, semantic_analysis::*, type_system::*, }; use ast_node::typed_expression::check_function_arguments_arity; use std::collections::{HashMap, VecDeque}; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{constants, integer_bits::IntegerBits}; use sway_types::{constants::CONTRACT_CALL_COINS_PARAMETER_NAME, Spanned}; use sway_types::{Ident, Span}; #[allow(clippy::too_many_arguments)] pub(crate) fn type_check_method_application( + handler: &Handler, mut ctx: TypeCheckContext, mut method_name_binding: TypeBinding, contract_call_params: Vec, arguments: Vec, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -34,43 +34,40 @@ pub(crate) fn type_check_method_application( .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - args_buf.push_back(check!( - ty::TyExpression::type_check(ctx, arg.clone()), - ty::TyExpression::error(span.clone(), engines), - warnings, - errors - )); + args_buf.push_back( + ty::TyExpression::type_check(handler, ctx, arg.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(span.clone(), engines)), + ); } // resolve the method name to a typed function declaration and type_check - let (decl_ref, call_path_typeid) = check!( - resolve_method_name(ctx.by_ref(), &mut method_name_binding, args_buf.clone()), - return err(warnings, errors), - warnings, - errors - ); + let (decl_ref, call_path_typeid) = resolve_method_name( + handler, + ctx.by_ref(), + &mut method_name_binding, + args_buf.clone(), + )?; let mut method = decl_engine.get_function(&decl_ref); // check the method visibility if span.source_id() != method.span.source_id() && method.visibility.is_private() { - errors.push(CompileError::CallingPrivateLibraryMethod { + return Err(handler.emit_err(CompileError::CallingPrivateLibraryMethod { name: method.name.as_str().to_string(), span, - }); - return err(warnings, errors); + })); } // check the function storage purity if !method.is_contract_call { // 'method.purity' is that of the callee, 'opts.purity' of the caller. if !ctx.purity().can_call(method.purity) { - errors.push(CompileError::StorageAccessMismatch { + handler.emit_err(CompileError::StorageAccessMismatch { attrs: promote_purity(ctx.purity(), method.purity).to_attribute_syntax(), span: method_name_binding.inner.easy_name().span(), }); } if !contract_call_params.is_empty() { - errors.push(CompileError::CallParamForNonContractCallMethod { + handler.emit_err(CompileError::CallParamForNonContractCallMethod { span: contract_call_params[0].name.span(), }); } @@ -90,7 +87,7 @@ pub(crate) fn type_check_method_application( .count() > 1 { - errors.push(CompileError::ContractCallParamRepeated { + handler.emit_err(CompileError::ContractCallParamRepeated { param_name: param_name.to_string(), span: span.clone(), }); @@ -118,16 +115,12 @@ pub(crate) fn type_check_method_application( .with_type_annotation(type_annotation); contract_call_params_map.insert( param.name.to_string(), - check!( - ty::TyExpression::type_check(ctx, param.value), - ty::TyExpression::error(span.clone(), engines), - warnings, - errors - ), + ty::TyExpression::type_check(handler, ctx, param.value) + .unwrap_or_else(|_| ty::TyExpression::error(span.clone(), engines)), ); } _ => { - errors.push(CompileError::UnrecognizedContractParam { + handler.emit_err(CompileError::UnrecognizedContractParam { param_name: param.name.to_string(), span: param.name.span().clone(), }); @@ -148,11 +141,12 @@ pub(crate) fn type_check_method_application( .attributes .contains_key(&crate::transform::AttributeKind::Payable) { - errors.push(CompileError::CoinsPassedToNonPayableMethod { - fn_name: method.name, - span, - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::CoinsPassedToNonPayableMethod { + fn_name: method.name, + span, + }), + ); } } } @@ -166,11 +160,12 @@ pub(crate) fn type_check_method_application( // check if the user calls an ABI supertrait's method (those are private) // as a contract method if let TypeInfo::ContractCaller { .. } = type_engine.get(first_arg.return_type) { - errors.push(CompileError::AbiSupertraitMethodCallAsContractCall { - fn_name: method_name.clone(), - span: span.clone(), - }); - return err(warnings, errors); + return Err(handler.emit_err( + CompileError::AbiSupertraitMethodCallAsContractCall { + fn_name: method_name.clone(), + span, + }, + )); } } is_method_call_syntax_used = true; @@ -180,11 +175,12 @@ pub(crate) fn type_check_method_application( .map(|f| f.is_self()) .unwrap_or_default(); if !is_first_param_self { - errors.push(CompileError::AssociatedFunctionCalledAsMethod { - fn_name: method_name.clone(), - span, - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::AssociatedFunctionCalledAsMethod { + fn_name: method_name.clone(), + span, + }), + ); } } } @@ -192,51 +188,41 @@ pub(crate) fn type_check_method_application( // Validate mutability of self. Check that the variable that the method is called on is mutable // _if_ the method requires mutable self. fn mutability_check( + handler: &Handler, ctx: &TypeCheckContext, method_name_binding: &TypeBinding, span: &Span, exp: &ty::TyExpressionVariant, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(), ErrorEmitted> { match exp { ty::TyExpressionVariant::VariableExpression { name, .. } => { - let unknown_decl = check!( - ctx.namespace.resolve_symbol(name).cloned(), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = ctx + .namespace + .resolve_symbol(&Handler::default(), name) + .cloned()?; let is_decl_mutable = match unknown_decl { ty::TyDecl::ConstantDecl { .. } => false, _ => { - let variable_decl = check!( - unknown_decl.expect_variable().cloned(), - return err(warnings, errors), - warnings, - errors - ); + let variable_decl = unknown_decl.expect_variable(handler).cloned()?; variable_decl.mutability.is_mutable() } }; if !is_decl_mutable { - errors.push(CompileError::MethodRequiresMutableSelf { + return Err(handler.emit_err(CompileError::MethodRequiresMutableSelf { method_name: method_name_binding.inner.easy_name(), variable_name: name.clone(), span: span.clone(), - }); - return err(warnings, errors); + })); } - ok((), warnings, errors) + Ok(()) } ty::TyExpressionVariant::StructFieldAccess { prefix, .. } => { - mutability_check(ctx, method_name_binding, span, &prefix.expression) + mutability_check(handler, ctx, method_name_binding, span, &prefix.expression) } - _ => ok((), warnings, errors), + _ => Ok(()), } } @@ -248,12 +234,7 @@ pub(crate) fn type_check_method_application( ) = (args_buf.get(0), method.parameters.get(0)) { if *is_mutable { - check!( - mutability_check(&ctx, &method_name_binding, &span, exp), - return err(warnings, errors), - warnings, - errors - ); + mutability_check(handler, &ctx, &method_name_binding, &span, exp)?; } } @@ -298,30 +279,24 @@ pub(crate) fn type_check_method_application( Some(TypeInfo::ContractCaller { address, .. }) => match address { Some(address) => address, None => { - errors.push(CompileError::ContractAddressMustBeKnown { + return Err(handler.emit_err(CompileError::ContractAddressMustBeKnown { span: call_path.span(), - }); - return err(warnings, errors); + })); } }, None => { - errors.push(CompileError::ContractCallsItsOwnMethod { span }); - return err(warnings, errors); + return Err(handler.emit_err(CompileError::ContractCallsItsOwnMethod { span })); } _ => { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "Attempted to find contract address of non-contract-call.", span, - )); - return err(warnings, errors); + ))); } }; - let func_selector = check!( - method.to_fn_selector_value(engines), - [0; 4], - warnings, - errors - ); + let func_selector = method + .to_fn_selector_value(handler, engines) + .unwrap_or([0; 4]); let contract_caller = contract_caller.unwrap(); Some(ty::ContractCallParams { func_selector, @@ -333,25 +308,18 @@ pub(crate) fn type_check_method_application( }; // check that the number of parameters and the number of the arguments is the same - check!( - check_function_arguments_arity( - args_buf.len(), - &method, - &call_path, - is_method_call_syntax_used - ), - return err(warnings, errors), - warnings, - errors - ); + + check_function_arguments_arity( + handler, + args_buf.len(), + &method, + &call_path, + is_method_call_syntax_used, + )?; // unify the types of the arguments with the types of the parameters from the function declaration - let typed_arguments_with_names = check!( - unify_arguments_and_parameters(ctx.by_ref(), args_buf, &method.parameters), - return err(warnings, errors), - warnings, - errors - ); + let typed_arguments_with_names = + unify_arguments_and_parameters(handler, ctx.by_ref(), args_buf, &method.parameters)?; // Retrieve the implemented traits for the type of the return type and // insert them in the broader namespace. @@ -361,16 +329,12 @@ pub(crate) fn type_check_method_application( // Handle the trait constraints. This includes checking to see if the trait // constraints are satisfied and replacing old decl ids based on the // constraint with new decl ids based on the new type. - let decl_mapping = check!( - TypeParameter::gather_decl_mapping_from_trait_constraints( - ctx.by_ref(), - &method.type_parameters, - &call_path.span() - ), - return err(warnings, errors), - warnings, - errors - ); + let decl_mapping = TypeParameter::gather_decl_mapping_from_trait_constraints( + handler, + ctx.by_ref(), + &method.type_parameters, + &call_path.span(), + )?; method.replace_decls(&decl_mapping, ctx.engines()); let return_type = method.return_type.type_id; let new_decl_ref = decl_engine @@ -391,62 +355,63 @@ pub(crate) fn type_check_method_application( span, }; - ok(exp, warnings, errors) + Ok(exp) } /// Unifies the types of the arguments with the types of the parameters. Returns /// a list of the arguments with the names of the corresponding parameters. fn unify_arguments_and_parameters( + handler: &Handler, ctx: TypeCheckContext, arguments: VecDeque, parameters: &[ty::TyFunctionParameter], -) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result, ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); let mut typed_arguments_and_names = vec![]; + let mut error_emitted = None; for (arg, param) in arguments.into_iter().zip(parameters.iter()) { // unify the type of the argument with the type of the param - check!( - CompileResult::from(type_engine.unify_with_self( - engines, - arg.return_type, - param.type_argument.type_id, - ctx.self_type(), - &arg.span, - "This argument's type is not castable to the declared parameter type.", - Some(CompileError::ArgumentParameterTypeMismatch { - span: arg.span.clone(), - provided: engines.help_out(arg.return_type).to_string(), - should_be: engines.help_out(param.type_argument.type_id).to_string(), - }) - )), - continue, - warnings, - errors + let (warnings, errors) = type_engine.unify_with_self( + engines, + arg.return_type, + param.type_argument.type_id, + ctx.self_type(), + &arg.span, + "This argument's type is not castable to the declared parameter type.", + Some(CompileError::ArgumentParameterTypeMismatch { + span: arg.span.clone(), + provided: engines.help_out(arg.return_type).to_string(), + should_be: engines.help_out(param.type_argument.type_id).to_string(), + }), ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors.clone() { + error_emitted = Some(handler.emit_err(err)); + } + if !errors.is_empty() { + continue; + } typed_arguments_and_names.push((param.name.clone(), arg)); } - if errors.is_empty() { - ok(typed_arguments_and_names, warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(typed_arguments_and_names) } } pub(crate) fn resolve_method_name( + handler: &Handler, mut ctx: TypeCheckContext, method_name: &mut TypeBinding, arguments: VecDeque, -) -> CompileResult<(DeclRefFunction, TypeId)> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result<(DeclRefFunction, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -458,41 +423,31 @@ pub(crate) fn resolve_method_name( method_name, } => { // type check the call path - let type_id = check!( - call_path_binding.type_check_with_type_info(&mut ctx), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + let type_id = call_path_binding + .type_check_with_type_info(handler, &mut ctx) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); // find the module that the symbol is in let type_info_prefix = ctx .namespace .find_module_path(&call_path_binding.inner.prefixes); - check!( - ctx.namespace.root().check_submodule(&type_info_prefix), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace + .root() + .check_submodule(handler, &type_info_prefix)?; // find the method - let decl_ref = check!( - ctx.namespace.find_method_for_type( - type_id, - &type_info_prefix, - method_name, - ctx.self_type(), - ctx.type_annotation(), - &arguments, - None, - engines, - true - ), - return err(warnings, errors), - warnings, - errors - ); + let decl_ref = ctx.namespace.find_method_for_type( + handler, + type_id, + &type_info_prefix, + method_name, + ctx.self_type(), + ctx.type_annotation(), + &arguments, + None, + engines, + true, + )?; (decl_ref, type_id) } @@ -520,22 +475,18 @@ pub(crate) fn resolve_method_name( .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown)); // find the method - let decl_ref = check!( - ctx.namespace.find_method_for_type( - type_id, - &module_path, - &call_path.suffix, - ctx.self_type(), - ctx.type_annotation(), - &arguments, - None, - engines, - true - ), - return err(warnings, errors), - warnings, - errors - ); + let decl_ref = ctx.namespace.find_method_for_type( + handler, + type_id, + &module_path, + &call_path.suffix, + ctx.self_type(), + ctx.type_annotation(), + &arguments, + None, + engines, + true, + )?; (decl_ref, type_id) } @@ -550,22 +501,18 @@ pub(crate) fn resolve_method_name( .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown)); // find the method - let decl_ref = check!( - ctx.namespace.find_method_for_type( - type_id, - &module_path, - method_name, - ctx.self_type(), - ctx.type_annotation(), - &arguments, - None, - engines, - true - ), - return err(warnings, errors), - warnings, - errors - ); + let decl_ref = ctx.namespace.find_method_for_type( + handler, + type_id, + &module_path, + method_name, + ctx.self_type(), + ctx.type_annotation(), + &arguments, + None, + engines, + true, + )?; (decl_ref, type_id) } @@ -579,22 +526,18 @@ pub(crate) fn resolve_method_name( let type_info_prefix = vec![]; // find the method - let decl_ref = check!( - ctx.namespace.find_method_for_type( - type_id, - &type_info_prefix, - method_name, - ctx.self_type(), - ctx.type_annotation(), - &arguments, - Some(as_trait.clone()), - engines, - true - ), - return err(warnings, errors), - warnings, - errors - ); + let decl_ref = ctx.namespace.find_method_for_type( + handler, + type_id, + &type_info_prefix, + method_name, + ctx.self_type(), + ctx.type_annotation(), + &arguments, + Some(as_trait.clone()), + engines, + true, + )?; (decl_ref, type_id) } @@ -604,17 +547,13 @@ pub(crate) fn resolve_method_name( // monomorphize the function declaration let method_name_span = method_name.span(); - check!( - ctx.monomorphize( - &mut func_decl, - method_name.type_arguments.to_vec_mut(), - EnforceTypeArguments::No, - &method_name_span, - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut func_decl, + method_name.type_arguments.to_vec_mut(), + EnforceTypeArguments::No, + &method_name_span, + )?; if let Some(implementing_type) = &func_decl.implementing_type { func_decl @@ -628,5 +567,5 @@ pub(crate) fn resolve_method_name( .insert(func_decl) .with_parent(ctx.engines.de(), (*decl_ref.id()).into()); - ok((decl_ref, type_id), warnings, errors) + Ok((decl_ref, type_id)) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs index c698fb9651d..8a7f4e71a2c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs @@ -1,31 +1,23 @@ +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Ident, Span, Spanned}; -use crate::{ - error::{err, ok}, - language::ty, - CompileResult, Engines, -}; +use crate::{language::ty, Engines}; pub(crate) fn instantiate_struct_field_access( + handler: &Handler, engines: &Engines, parent: ty::TyExpression, field_to_access: Ident, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result { let type_engine = engines.te(); let field_instantiation_span = field_to_access.span(); - let field = check!( - type_engine.get(parent.return_type).apply_subfields( - engines, - &[field_to_access], - &parent.span - ), - return err(warnings, errors), - warnings, - errors - ); + let field = type_engine.get(parent.return_type).apply_subfields( + handler, + engines, + &[field_to_access], + &parent.span, + )?; let exp = ty::TyExpression { expression: ty::TyExpressionVariant::StructFieldAccess { resolved_type_of_parent: parent.return_type, @@ -36,5 +28,5 @@ pub(crate) fn instantiate_struct_field_access( return_type: field.type_argument.type_id, span, }; - ok(exp, warnings, errors) + Ok(exp) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 1797f30dddf..fb111b76d4e 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -1,23 +1,23 @@ -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span, Spanned}; use crate::{ decl_engine::DeclRefStruct, - error::*, language::{parsed::*, ty, CallPath}, semantic_analysis::TypeCheckContext, type_system::*, }; pub(crate) fn struct_instantiation( + handler: &Handler, mut ctx: TypeCheckContext, mut call_path_binding: TypeBinding, fields: Vec, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -25,8 +25,8 @@ pub(crate) fn struct_instantiation( // We need the call_path_binding to have types that point to proper definitions so the LSP can // look for them, but its types haven't been resolved yet. // To that end we do a dummy type check which has the side effect of resolving the types. - let _: CompileResult<(DeclRefStruct, _, _)> = - TypeBinding::type_check(&mut call_path_binding, ctx.by_ref()); + let _: Result<(DeclRefStruct, _, _), _> = + TypeBinding::type_check(&mut call_path_binding, &Handler::default(), ctx.by_ref()); let TypeBinding { inner: CallPath { @@ -37,11 +37,12 @@ pub(crate) fn struct_instantiation( } = call_path_binding.clone(); if let TypeArgs::Prefix(_) = type_arguments { - errors.push(CompileError::DoesNotTakeTypeArgumentsAsPrefix { - name: suffix, - span: type_arguments.span(), - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::DoesNotTakeTypeArgumentsAsPrefix { + name: suffix, + span: type_arguments.span(), + }), + ); } let type_arguments = type_arguments.to_vec(); @@ -49,10 +50,9 @@ pub(crate) fn struct_instantiation( let type_info = match (suffix.as_str(), type_arguments.is_empty()) { ("Self", true) => TypeInfo::SelfType, ("Self", false) => { - errors.push(CompileError::TypeArgumentsNotAllowed { + return Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span: suffix.span(), - }); - return err(warnings, errors); + })); } (_, true) => TypeInfo::Custom { call_path: suffix.into(), @@ -66,63 +66,44 @@ pub(crate) fn struct_instantiation( // find the module that the struct decl is in let type_info_prefix = ctx.namespace.find_module_path(&prefixes); - check!( - ctx.namespace.root().check_submodule(&type_info_prefix), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace + .root() + .check_submodule(handler, &type_info_prefix)?; // resolve the type of the struct decl - let type_id = check!( - ctx.resolve_type_with_self( + let type_id = ctx + .resolve_type_with_self( + handler, type_engine.insert(engines, type_info), &inner_span, EnforceTypeArguments::No, - Some(&type_info_prefix) - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + Some(&type_info_prefix), + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); // extract the struct name and fields from the type info let type_info = type_engine.get(type_id); - let struct_ref = check!( - type_info.expect_struct(engines, &span), - return err(warnings, errors), - warnings, - errors - ); + let struct_ref = type_info.expect_struct(handler, engines, &span)?; let struct_decl = decl_engine.get_struct(&struct_ref); let struct_name = struct_decl.call_path.suffix; let struct_fields = struct_decl.fields; let mut struct_fields = struct_fields; - let typed_fields = check!( - type_check_field_arguments( - ctx.by_ref(), - &fields, - &struct_name, - &mut struct_fields, - &span - ), - return err(warnings, errors), - warnings, - errors - ); - - check!( - unify_field_arguments_and_struct_fields(ctx.by_ref(), &typed_fields, &struct_fields,), - return err(warnings, errors), - warnings, - errors - ); + let typed_fields = type_check_field_arguments( + handler, + ctx.by_ref(), + &fields, + &struct_name, + &mut struct_fields, + &span, + )?; + + unify_field_arguments_and_struct_fields(handler, ctx.by_ref(), &typed_fields, &struct_fields)?; // check that there are no extra fields for field in fields { if !struct_fields.iter().any(|x| x.name == field.name) { - errors.push(CompileError::StructDoesNotHaveField { + handler.emit_err(CompileError::StructDoesNotHaveField { field_name: field.name.clone(), struct_name: struct_name.clone(), span: field.span, @@ -130,12 +111,7 @@ pub(crate) fn struct_instantiation( } } - check!( - type_id.check_type_parameter_bounds(&ctx, &span, vec![]), - return err(warnings, errors), - warnings, - errors - ); + type_id.check_type_parameter_bounds(handler, &ctx, &span, vec![])?; let exp = ty::TyExpression { expression: ty::TyExpressionVariant::StructExpression { @@ -148,20 +124,18 @@ pub(crate) fn struct_instantiation( span, }; - ok(exp, warnings, errors) + Ok(exp) } /// Type checks the field arguments. fn type_check_field_arguments( + handler: &Handler, mut ctx: TypeCheckContext, fields: &[StructExpressionField], struct_name: &Ident, struct_fields: &mut [ty::TyStructField], span: &Span, -) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result, ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -174,12 +148,10 @@ fn type_check_field_arguments( .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - let value = check!( - ty::TyExpression::type_check(ctx, field.value.clone()), - continue, - warnings, - errors - ); + let value = match ty::TyExpression::type_check(handler, ctx, field.value.clone()) { + Ok(res) => res, + Err(_) => continue, + }; typed_fields.push(ty::TyStructExpressionField { value, name: field.name.clone(), @@ -187,7 +159,7 @@ fn type_check_field_arguments( struct_field.span = field.value.span.clone(); } None => { - errors.push(CompileError::StructMissingField { + handler.emit_err(CompileError::StructMissingField { field_name: struct_field.name.clone(), struct_name: struct_name.clone(), span: span.clone(), @@ -204,43 +176,44 @@ fn type_check_field_arguments( } } - ok(typed_fields, warnings, errors) + Ok(typed_fields) } /// Unifies the field arguments and the types of the fields from the struct /// definition. fn unify_field_arguments_and_struct_fields( + handler: &Handler, ctx: TypeCheckContext, typed_fields: &[ty::TyStructExpressionField], struct_fields: &[ty::TyStructField], -) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result<(), ErrorEmitted> { let type_engine = ctx.engines.te(); let engines = ctx.engines(); + let mut error_emitted = None; for struct_field in struct_fields.iter() { if let Some(typed_field) = typed_fields.iter().find(|x| x.name == struct_field.name) { - check!( - CompileResult::from(type_engine.unify( - engines, - typed_field.value.return_type, - struct_field.type_argument.type_id, - &typed_field.value.span, - "Struct field's type must match the type specified in its declaration.", - None, - )), - continue, - warnings, - errors + let (warnings, errors) = type_engine.unify( + engines, + typed_field.value.return_type, + struct_field.type_argument.type_id, + &typed_field.value.span, + "Struct field's type must match the type specified in its declaration.", + None, ); + + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + error_emitted = Some(handler.emit_err(err)); + } } } - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs index 26980066468..2a8ea3bb3d1 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs @@ -1,29 +1,20 @@ +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; -use crate::{ - error::{err, ok}, - language::ty, - CompileError, CompileResult, Engines, -}; +use crate::{language::ty, CompileError, Engines}; pub(crate) fn instantiate_tuple_index_access( + handler: &Handler, engines: &Engines, parent: ty::TyExpression, index: usize, index_span: Span, span: Span, -) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; +) -> Result { let type_engine = engines.te(); let mut tuple_type_arg_to_access = None; let type_info = type_engine.get(parent.return_type); - let type_args = check!( - type_info.expect_tuple(engines, parent.span.as_str(), &parent.span), - return err(warnings, errors), - warnings, - errors - ); + let type_args = type_info.expect_tuple(handler, engines, parent.span.as_str(), &parent.span)?; for (pos, type_arg) in type_args.iter().enumerate() { if pos == index { tuple_type_arg_to_access = Some(type_arg.clone()); @@ -32,12 +23,11 @@ pub(crate) fn instantiate_tuple_index_access( let tuple_type_arg_to_access = match tuple_type_arg_to_access { Some(tuple_type_arg_to_access) => tuple_type_arg_to_access, None => { - errors.push(CompileError::TupleIndexOutOfBounds { + return Err(handler.emit_err(CompileError::TupleIndexOutOfBounds { index, count: type_args.len(), span: index_span, - }); - return err(warnings, errors); + })); } }; let exp = ty::TyExpression { @@ -50,5 +40,5 @@ pub(crate) fn instantiate_tuple_index_access( return_type: tuple_type_arg_to_access.type_id, span, }; - ok(exp, warnings, errors) + Ok(exp) } diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 85f392b7cf2..a469cece311 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -7,7 +7,6 @@ pub(crate) use expression::*; pub(crate) use modes::*; use crate::{ - error::*, language::{parsed::*, ty}, semantic_analysis::*, type_system::*, @@ -15,14 +14,18 @@ use crate::{ Ident, }; -use sway_error::warning::Warning; +use sway_error::{ + handler::{ErrorEmitted, Handler}, + warning::{CompileWarning, Warning}, +}; use sway_types::{span::Span, Spanned}; impl ty::TyAstNode { - pub(crate) fn type_check(ctx: TypeCheckContext, node: AstNode) -> CompileResult { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - + pub(crate) fn type_check( + handler: &Handler, + ctx: TypeCheckContext, + node: AstNode, + ) -> Result { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); @@ -35,32 +38,45 @@ impl ty::TyAstNode { } else { ctx.namespace.find_module_path(&a.call_path) }; - let mut res = match a.import_type { + let _ = match a.import_type { ImportType::Star => { // try a standard starimport first - let import = ctx.namespace.star_import(&path, engines, a.is_absolute); + let star_import_handler = Handler::default(); + let import = ctx.namespace.star_import( + &star_import_handler, + &path, + engines, + a.is_absolute, + ); if import.is_ok() { + handler.append(star_import_handler); import } else { // if it doesn't work it could be an enum star import if let Some((enum_name, path)) = path.split_last() { + let variant_import_handler = Handler::default(); let variant_import = ctx.namespace.variant_star_import( + &variant_import_handler, path, engines, enum_name, a.is_absolute, ); if variant_import.is_ok() { + handler.append(variant_import_handler); variant_import } else { + handler.append(star_import_handler); import } } else { + handler.append(star_import_handler); import } } } ImportType::SelfImport(_) => ctx.namespace.self_import( + handler, engines, &path, a.alias.clone(), @@ -68,7 +84,9 @@ impl ty::TyAstNode { ), ImportType::Item(ref s) => { // try a standard item import first + let item_import_handler = Handler::default(); let import = ctx.namespace.item_import( + &item_import_handler, engines, &path, s, @@ -77,11 +95,14 @@ impl ty::TyAstNode { ); if import.is_ok() { + handler.append(item_import_handler); import } else { // if it doesn't work it could be an enum variant import if let Some((enum_name, path)) = path.split_last() { + let variant_import_handler = Handler::default(); let variant_import = ctx.namespace.variant_import( + &variant_import_handler, engines, path, enum_name, @@ -90,18 +111,19 @@ impl ty::TyAstNode { a.is_absolute, ); if variant_import.is_ok() { + handler.append(variant_import_handler); variant_import } else { + handler.append(item_import_handler); import } } else { + handler.append(item_import_handler); import } } } }; - warnings.append(&mut res.warnings); - errors.append(&mut res.errors); ty::TyAstNodeContent::SideEffect(ty::TySideEffect { side_effect: ty::TySideEffectVariant::UseStatement(ty::TyUseStatement { alias: a.alias, @@ -116,33 +138,22 @@ impl ty::TyAstNode { side_effect: ty::TySideEffectVariant::IncludeStatement, }) } - AstNodeContent::Declaration(decl) => ty::TyAstNodeContent::Declaration(check!( - ty::TyDecl::type_check(ctx, decl), - return err(warnings, errors), - warnings, - errors - )), + AstNodeContent::Declaration(decl) => { + ty::TyAstNodeContent::Declaration(ty::TyDecl::type_check(handler, ctx, decl)?) + } AstNodeContent::Expression(expr) => { let ctx = ctx .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) .with_help_text(""); - let inner = check!( - ty::TyExpression::type_check(ctx, expr.clone()), - ty::TyExpression::error(expr.span(), engines), - warnings, - errors - ); + let inner = ty::TyExpression::type_check(handler, ctx, expr.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(expr.span(), engines)); ty::TyAstNodeContent::Expression(inner) } AstNodeContent::ImplicitReturnExpression(expr) => { let ctx = ctx.with_help_text("Implicit return must match up with block's type."); - let typed_expr = check!( - ty::TyExpression::type_check(ctx, expr.clone()), - ty::TyExpression::error(expr.span(), engines), - warnings, - errors - ); + let typed_expr = ty::TyExpression::type_check(handler, ctx, expr.clone()) + .unwrap_or_else(|_| ty::TyExpression::error(expr.span(), engines)); ty::TyAstNodeContent::ImplicitReturnExpression(typed_expr) } }, @@ -154,18 +165,19 @@ impl ty::TyAstNode { .. } = node { - let warning = Warning::UnusedReturnValue { - r#type: engines.help_out(node.type_info(type_engine)).to_string(), + if !node + .type_info(type_engine) + .can_safely_ignore(type_engine, decl_engine) + { + handler.emit_warn(CompileWarning { + warning_content: Warning::UnusedReturnValue { + r#type: engines.help_out(node.type_info(type_engine)).to_string(), + }, + span: node.span.clone(), + }) }; - assert_or_warn!( - node.type_info(type_engine) - .can_safely_ignore(type_engine, decl_engine), - warnings, - node.span.clone(), - warning - ); } - ok(node, warnings, errors) + Ok(node) } } diff --git a/sway-core/src/semantic_analysis/coins_analysis.rs b/sway-core/src/semantic_analysis/coins_analysis.rs index d5df49cb5a3..09ff413e049 100644 --- a/sway-core/src/semantic_analysis/coins_analysis.rs +++ b/sway-core/src/semantic_analysis/coins_analysis.rs @@ -1,3 +1,5 @@ +use sway_error::handler::Handler; + use crate::{decl_engine::DeclEngine, language::ty, Namespace}; // This analysis checks if an expression is known statically to evaluate @@ -20,7 +22,7 @@ pub fn possibly_nonzero_u64_expression( None => false, }, VariableExpression { name, .. } => { - match namespace.resolve_symbol(name).value { + match namespace.resolve_symbol(&Handler::default(), name).ok() { Some(ty_decl) => { match ty_decl { ty::TyDecl::VariableDecl(var_decl) => { diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index 44361e01a4c..b112c570ee6 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -1,5 +1,6 @@ +use sway_error::handler::{ErrorEmitted, Handler}; + use crate::{ - error::*, language::{parsed::*, ty, ModName}, semantic_analysis::*, }; @@ -8,7 +9,11 @@ impl ty::TyModule { /// Type-check the given parsed module to produce a typed module. /// /// Recursively type-checks submodules first. - pub fn type_check(mut ctx: TypeCheckContext, parsed: &ParseModule) -> CompileResult { + pub fn type_check( + handler: &Handler, + mut ctx: TypeCheckContext, + parsed: &ParseModule, + ) -> Result { let ParseModule { submodules, tree, @@ -18,27 +23,27 @@ impl ty::TyModule { } = parsed; // Type-check submodules first in order of declaration. - let mut submodules_res = ok(vec![], vec![], vec![]); - for (name, submodule) in submodules { - let submodule_res = ty::TySubmodule::type_check(ctx.by_ref(), name.clone(), submodule); - submodules_res = submodules_res.flat_map(|mut submodules| { - submodule_res.map(|submodule| { - submodules.push((name.clone(), submodule)); - submodules - }) - }); - } + let submodules_res = submodules + .iter() + .map(|(name, submodule)| { + Ok(( + name.clone(), + ty::TySubmodule::type_check(handler, ctx.by_ref(), name.clone(), submodule)?, + )) + }) + .collect::, _>>(); // TODO: Ordering should be solved across all modules prior to the beginning of type-check. let ordered_nodes_res = node_dependencies::order_ast_nodes_by_dependency( + handler, ctx.engines(), tree.root_nodes.clone(), ); let typed_nodes_res = ordered_nodes_res - .flat_map(|ordered_nodes| Self::type_check_nodes(ctx.by_ref(), ordered_nodes)); + .and_then(|ordered_nodes| Self::type_check_nodes(handler, ctx.by_ref(), ordered_nodes)); - submodules_res.flat_map(|submodules| { + submodules_res.and_then(|submodules| { typed_nodes_res.map(|all_nodes| Self { span: span.clone(), submodules, @@ -50,33 +55,33 @@ impl ty::TyModule { } fn type_check_nodes( + handler: &Handler, mut ctx: TypeCheckContext, nodes: Vec, - ) -> CompileResult> { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); + ) -> Result, ErrorEmitted> { let typed_nodes = nodes .into_iter() - .map(|node| ty::TyAstNode::type_check(ctx.by_ref(), node)) - .filter_map(|res| res.ok(&mut warnings, &mut errors)) + .map(|node| ty::TyAstNode::type_check(handler, ctx.by_ref(), node)) + .filter_map(|res| res.ok()) .collect(); - ok(typed_nodes, warnings, errors) + Ok(typed_nodes) } } impl ty::TySubmodule { pub fn type_check( + handler: &Handler, parent_ctx: TypeCheckContext, mod_name: ModName, submodule: &ParseSubmodule, - ) -> CompileResult { + ) -> Result { let ParseSubmodule { module, mod_name_span, visibility, } = submodule; parent_ctx.enter_submodule(mod_name, *visibility, module.span.clone(), |submod_ctx| { - let module_res = ty::TyModule::type_check(submod_ctx, module); + let module_res = ty::TyModule::type_check(handler, submod_ctx, module); module_res.map(|module| ty::TySubmodule { module, mod_name_span: mod_name_span.clone(), diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index 5612735b683..6cd92aaf9cf 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -1,7 +1,6 @@ use crate::{ decl_engine::*, engine_threading::Engines, - error::*, language::{ ty::{self, TyDecl, TyStorageDecl}, CallPath, @@ -13,7 +12,10 @@ use crate::{ use super::TraitMap; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{span::Span, Spanned}; use std::sync::Arc; @@ -57,19 +59,19 @@ impl Items { pub fn apply_storage_load( &self, + handler: &Handler, engines: &Engines, fields: Vec, storage_fields: &[ty::TyStorageField], storage_keyword_span: Span, - ) -> CompileResult<(ty::TyStorageAccess, TypeId)> { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result<(ty::TyStorageAccess, TypeId), ErrorEmitted> { let type_engine = engines.te(); let decl_engine = engines.de(); match self.declared_storage { Some(ref decl_ref) => { let storage = decl_engine.get_storage(&decl_ref.id().clone()); storage.apply_storage_load( + handler, type_engine, decl_engine, fields, @@ -77,26 +79,24 @@ impl Items { storage_keyword_span, ) } - None => { - errors.push(CompileError::NoDeclaredStorage { - span: fields[0].span(), - }); - err(warnings, errors) - } + None => Err(handler.emit_err(CompileError::NoDeclaredStorage { + span: fields[0].span(), + })), } } - pub fn set_storage_declaration(&mut self, decl_ref: DeclRefStorage) -> CompileResult<()> { + pub fn set_storage_declaration( + &mut self, + handler: &Handler, + decl_ref: DeclRefStorage, + ) -> Result<(), ErrorEmitted> { if self.declared_storage.is_some() { - return err( - vec![], - vec![CompileError::MultipleStorageDeclarations { - span: decl_ref.span(), - }], - ); + return Err(handler.emit_err(CompileError::MultipleStorageDeclarations { + span: decl_ref.span(), + })); } self.declared_storage = Some(decl_ref); - ok((), vec![], vec![]) + Ok(()) } pub fn get_all_declared_symbols(&self) -> impl Iterator { @@ -105,37 +105,36 @@ impl Items { pub(crate) fn insert_symbol( &mut self, + handler: &Handler, name: Ident, item: ty::TyDecl, const_shadowing_mode: ConstShadowingMode, - ) -> CompileResult<()> { - let mut errors = vec![]; - + ) -> Result<(), ErrorEmitted> { let append_shadowing_error = - |decl: &ty::TyDecl, - item: &ty::TyDecl, - const_shadowing_mode: ConstShadowingMode, - errors: &mut Vec| { + |decl: &ty::TyDecl, item: &ty::TyDecl, const_shadowing_mode: ConstShadowingMode| { use ty::TyDecl::*; match (decl, &item, const_shadowing_mode) { // variable shadowing a constant (ConstantDecl { .. }, VariableDecl { .. }, _) => { - errors.push(CompileError::VariableShadowsConstant { name: name.clone() }) + handler + .emit_err(CompileError::VariableShadowsConstant { name: name.clone() }); } // constant shadowing a variable (VariableDecl { .. }, ConstantDecl { .. }, _) => { - errors.push(CompileError::ConstantShadowsVariable { name: name.clone() }) + handler + .emit_err(CompileError::ConstantShadowsVariable { name: name.clone() }); } // constant shadowing a constant outside function body (ConstantDecl { .. }, ConstantDecl { .. }, ConstShadowingMode::ItemStyle) => { - errors.push(CompileError::MultipleDefinitionsOfConstant { + handler.emit_err(CompileError::MultipleDefinitionsOfConstant { name: name.clone(), span: name.span(), - }) + }); } // constant shadowing a constant within function body (ConstantDecl { .. }, ConstantDecl { .. }, ConstShadowingMode::Sequential) => { - errors.push(CompileError::ConstantShadowsConstant { name: name.clone() }) + handler + .emit_err(CompileError::ConstantShadowsConstant { name: name.clone() }); } // type or type alias shadowing another type or type alias // trait/abi shadowing another trait/abi @@ -152,28 +151,31 @@ impl Items { | TraitDecl { .. } | AbiDecl { .. }, _, - ) => errors.push(CompileError::MultipleDefinitionsOfName { - name: name.clone(), - span: name.span(), - }), + ) => { + handler.emit_err(CompileError::MultipleDefinitionsOfName { + name: name.clone(), + span: name.span(), + }); + } // Generic parameter shadowing another generic parameter (GenericTypeForFunctionScope { .. }, GenericTypeForFunctionScope { .. }, _) => { - errors.push(CompileError::GenericShadowsGeneric { name: name.clone() }); + handler + .emit_err(CompileError::GenericShadowsGeneric { name: name.clone() }); } _ => {} } }; if let Some(decl) = self.symbols.get(&name) { - append_shadowing_error(decl, &item, const_shadowing_mode, &mut errors); + append_shadowing_error(decl, &item, const_shadowing_mode); } if let Some((_, GlobImport::No, decl, _)) = self.use_synonyms.get(&name) { - append_shadowing_error(decl, &item, const_shadowing_mode, &mut errors); + append_shadowing_error(decl, &item, const_shadowing_mode); } self.symbols.insert(name, item); - ok((), vec![], errors) + Ok(()) } pub(crate) fn check_symbol(&self, name: &Ident) -> Result<&ty::TyDecl, CompileError> { @@ -198,9 +200,9 @@ impl Items { } pub fn get_impl_spans_for_decl(&self, engines: &Engines, ty_decl: &TyDecl) -> Vec { + let handler = Handler::default(); ty_decl - .return_type(engines) - .value + .return_type(&handler, engines) .map(|type_id| { self.implemented_traits .get_impl_spans_for_type(engines, &type_id) @@ -240,17 +242,15 @@ impl Items { pub(crate) fn get_storage_field_descriptors( &self, + handler: &Handler, decl_engine: &DeclEngine, - ) -> CompileResult> { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result, ErrorEmitted> { match self.get_declared_storage(decl_engine) { - Some(storage) => ok(storage.fields, warnings, errors), + Some(storage) => Ok(storage.fields), None => { let msg = "unknown source location"; let span = Span::new(Arc::from(msg), 0, msg.len(), None).unwrap(); - errors.push(CompileError::NoDeclaredStorage { span }); - err(warnings, errors) + Err(handler.emit_err(CompileError::NoDeclaredStorage { span })) } } } @@ -259,32 +259,24 @@ impl Items { /// the second is the [ResolvedType] of its parent, for control-flow analysis. pub(crate) fn find_subfield_type( &self, + handler: &Handler, engines: &Engines, base_name: &Ident, projections: &[ty::ProjectionKind], - ) -> CompileResult<(TypeId, TypeId)> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(TypeId, TypeId), ErrorEmitted> { let type_engine = engines.te(); let decl_engine = engines.de(); let symbol = match self.symbols.get(base_name).cloned() { Some(s) => s, None => { - errors.push(CompileError::UnknownVariable { + return Err(handler.emit_err(CompileError::UnknownVariable { var_name: base_name.clone(), span: base_name.span(), - }); - return err(warnings, errors); + })); } }; - let mut symbol = check!( - symbol.return_type(engines), - return err(warnings, errors), - warnings, - errors - ); + let mut symbol = symbol.return_type(handler, engines)?; let mut symbol_span = base_name.span(); let mut parent_rover = symbol; let mut full_name_for_error = base_name.to_string(); @@ -293,8 +285,7 @@ impl Items { let resolved_type = match type_engine.to_typeinfo(symbol, &symbol_span) { Ok(resolved_type) => resolved_type, Err(error) => { - errors.push(CompileError::TypeError(error)); - return err(warnings, errors); + return Err(handler.emit_err(CompileError::TypeError(error))); } }; match (resolved_type, projection) { @@ -328,13 +319,12 @@ impl Items { .map(|field| field.name.as_str()) .collect::>(); - errors.push(CompileError::FieldNotFound { + return Err(handler.emit_err(CompileError::FieldNotFound { field_name: field_name.clone(), struct_name: struct_decl.call_path.suffix, available_fields: available_fields.join(", "), span: field_name.span(), - }); - return err(warnings, errors); + })); } }; parent_rover = symbol; @@ -353,12 +343,11 @@ impl Items { let field_type = match field_type_opt { Some(field_type) => field_type, None => { - errors.push(CompileError::TupleIndexOutOfBounds { + return Err(handler.emit_err(CompileError::TupleIndexOutOfBounds { index: *index, count: fields.len(), span: Span::join(full_span_for_error, index_span.clone()), - }); - return err(warnings, errors); + })); } }; parent_rover = symbol; @@ -377,30 +366,27 @@ impl Items { full_span_for_error = index_span.clone(); } (actually, ty::ProjectionKind::StructField { .. }) => { - errors.push(CompileError::FieldAccessOnNonStruct { + return Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { span: full_span_for_error, actually: engines.help_out(actually).to_string(), - }); - return err(warnings, errors); + })); } (actually, ty::ProjectionKind::TupleField { .. }) => { - errors.push(CompileError::NotATuple { + return Err(handler.emit_err(CompileError::NotATuple { name: full_name_for_error, span: full_span_for_error, actually: engines.help_out(actually).to_string(), - }); - return err(warnings, errors); + })); } (actually, ty::ProjectionKind::ArrayIndex { .. }) => { - errors.push(CompileError::NotIndexable { + return Err(handler.emit_err(CompileError::NotIndexable { name: full_name_for_error, span: full_span_for_error, actually: engines.help_out(actually).to_string(), - }); - return err(warnings, errors); + })); } } } - ok((symbol, parent_rover), warnings, errors) + Ok((symbol, parent_rover)) } } diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index dd4b14e066d..97522308c9e 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -1,7 +1,6 @@ use crate::{ decl_engine::DeclRef, engine_threading::Engines, - error::*, language::{ parsed::*, ty::{self, TyDecl}, @@ -158,8 +157,7 @@ impl Module { ns.root.module.is_external = true; ns.root.module.visibility = Visibility::Public; let type_check_ctx = TypeCheckContext::from_root(&mut ns, engines); - let typed_node = - ty::TyAstNode::type_check(type_check_ctx, ast_node).unwrap(&mut vec![], &mut vec![]); + let typed_node = ty::TyAstNode::type_check(handler, type_check_ctx, ast_node).unwrap(); // get the decl out of the typed node: // we know as an invariant this must be a const decl, as we hardcoded a const decl in // the above `format!`. if it isn't we report an @@ -218,10 +216,14 @@ impl Module { /// Lookup the submodule at the given path. /// /// This should be used rather than `Index` when we don't yet know whether the module exists. - pub(crate) fn check_submodule(&self, path: &[Ident]) -> CompileResult<&Module> { + pub(crate) fn check_submodule( + &self, + handler: &Handler, + path: &[Ident], + ) -> Result<&Module, ErrorEmitted> { match self.submodule(path) { - None => err(vec![], vec![module_not_found(path)]), - Some(module) => ok(module, vec![], vec![]), + None => Err(handler.emit_err(module_not_found(path))), + Some(module) => Ok(module), } } @@ -233,29 +235,17 @@ impl Module { /// Paths are assumed to be relative to `self`. pub(crate) fn star_import( &mut self, + handler: &Handler, src: &Path, dst: &Path, engines: &Engines, is_src_absolute: bool, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - - check!( - self.check_module_privacy(src, dst), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result<(), ErrorEmitted> { + self.check_module_privacy(handler, src, dst)?; let decl_engine = engines.de(); - let src_ns = check!( - self.check_submodule(src), - return err(warnings, errors), - warnings, - errors - ); + let src_ns = self.check_submodule(handler, src)?; let implemented_traits = src_ns.implemented_traits.clone(); let mut symbols_and_decls = vec![]; @@ -281,7 +271,7 @@ impl Module { ); } - ok((), warnings, errors) + Ok(()) } /// Given a path to a `src` module, create synonyms to every symbol in that module to the given @@ -292,29 +282,17 @@ impl Module { /// Paths are assumed to be relative to `self`. pub fn star_import_with_reexports( &mut self, + handler: &Handler, src: &Path, dst: &Path, engines: &Engines, is_src_absolute: bool, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - - check!( - self.check_module_privacy(src, dst), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result<(), ErrorEmitted> { + self.check_module_privacy(handler, src, dst)?; let decl_engine = engines.de(); - let src_ns = check!( - self.check_submodule(src), - return err(warnings, errors), - warnings, - errors - ); + let src_ns = self.check_submodule(handler, src)?; let implemented_traits = src_ns.implemented_traits.clone(); let use_synonyms = src_ns.use_synonyms.clone(); @@ -366,7 +344,7 @@ impl Module { try_add(symbol, path, decl); } - ok((), warnings, errors) + Ok(()) } /// Pull a single item from a `src` module and import it into the `dst` module. @@ -375,59 +353,56 @@ impl Module { /// import. pub(crate) fn self_import( &mut self, + handler: &Handler, engines: &Engines, src: &Path, dst: &Path, alias: Option, is_src_absolute: bool, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { let (last_item, src) = src.split_last().expect("guaranteed by grammar"); - self.item_import(engines, src, last_item, dst, alias, is_src_absolute) + self.item_import( + handler, + engines, + src, + last_item, + dst, + alias, + is_src_absolute, + ) } /// Pull a single `item` from the given `src` module and import it into the `dst` module. /// /// Paths are assumed to be relative to `self`. + #[allow(clippy::too_many_arguments)] pub(crate) fn item_import( &mut self, + handler: &Handler, engines: &Engines, src: &Path, item: &Ident, dst: &Path, alias: Option, is_src_absolute: bool, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - - check!( - self.check_module_privacy(src, dst), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result<(), ErrorEmitted> { + self.check_module_privacy(handler, src, dst)?; let decl_engine = engines.de(); - let src_ns = check!( - self.check_submodule(src), - return err(warnings, errors), - warnings, - errors - ); + let src_ns = self.check_submodule(handler, src)?; let mut impls_to_insert = TraitMap::default(); match src_ns.symbols.get(item).cloned() { Some(decl) => { if !decl.visibility(decl_engine).is_public() && !is_ancestor(src, dst) { - errors.push(CompileError::ImportPrivateSymbol { + handler.emit_err(CompileError::ImportPrivateSymbol { name: item.clone(), span: item.span(), }); } - let type_id = decl.return_type(engines).value; // if this is an enum or struct or function, import its implementations - if let Some(type_id) = type_id { + if let Ok(type_id) = decl.return_type(&Handler::default(), engines) { impls_to_insert.extend( src_ns .implemented_traits @@ -451,7 +426,7 @@ impl Module { let dst_ns = &mut self[dst]; let add_synonym = |name| { if let Some((_, GlobImport::No, _, _)) = dst_ns.use_synonyms.get(name) { - errors.push(CompileError::ShadowsOtherSymbol { name: name.clone() }); + handler.emit_err(CompileError::ShadowsOtherSymbol { name: name.clone() }); } dst_ns.use_synonyms.insert( name.clone(), @@ -469,18 +444,17 @@ impl Module { }; } None => { - errors.push(CompileError::SymbolNotFound { + return Err(handler.emit_err(CompileError::SymbolNotFound { name: item.clone(), span: item.span(), - }); - return err(warnings, errors); + })); } }; let dst_ns = &mut self[dst]; dst_ns.implemented_traits.extend(impls_to_insert, engines); - ok((), warnings, errors) + Ok(()) } /// Pull a single variant `variant` from the enum `enum_name` from the given `src` module and import it into the `dst` module. @@ -489,6 +463,7 @@ impl Module { #[allow(clippy::too_many_arguments)] // TODO: remove lint bypass once private modules are no longer experimental pub(crate) fn variant_import( &mut self, + handler: &Handler, engines: &Engines, src: &Path, enum_name: &Ident, @@ -496,29 +471,16 @@ impl Module { dst: &Path, alias: Option, is_src_absolute: bool, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - - check!( - self.check_module_privacy(src, dst), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result<(), ErrorEmitted> { + self.check_module_privacy(handler, src, dst)?; let decl_engine = engines.de(); - let src_ns = check!( - self.check_submodule(src), - return err(warnings, errors), - warnings, - errors - ); + let src_ns = self.check_submodule(handler, src)?; match src_ns.symbols.get(enum_name).cloned() { Some(decl) => { if !decl.visibility(decl_engine).is_public() && !is_ancestor(src, dst) { - errors.push(CompileError::ImportPrivateSymbol { + handler.emit_err(CompileError::ImportPrivateSymbol { name: enum_name.clone(), span: enum_name.span(), }); @@ -544,8 +506,9 @@ impl Module { let dst_ns = &mut self[dst]; let mut add_synonym = |name| { if let Some((_, GlobImport::No, _, _)) = dst_ns.use_synonyms.get(name) { - errors - .push(CompileError::ShadowsOtherSymbol { name: name.clone() }); + handler.emit_err(CompileError::ShadowsOtherSymbol { + name: name.clone(), + }); } dst_ns.use_synonyms.insert( name.clone(), @@ -571,30 +534,27 @@ impl Module { None => add_synonym(variant_name), }; } else { - errors.push(CompileError::SymbolNotFound { + return Err(handler.emit_err(CompileError::SymbolNotFound { name: variant_name.clone(), span: variant_name.span(), - }); - return err(warnings, errors); + })); } } else { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "Attempting to import variants of something that isn't an enum", enum_name.span(), - )); - return err(warnings, errors); + ))); } } None => { - errors.push(CompileError::SymbolNotFound { + return Err(handler.emit_err(CompileError::SymbolNotFound { name: enum_name.clone(), span: enum_name.span(), - }); - return err(warnings, errors); + })); } }; - ok((), warnings, errors) + Ok(()) } /// Pull all variants from the enum `enum_name` from the given `src` module and import them all into the `dst` module. @@ -602,34 +562,22 @@ impl Module { /// Paths are assumed to be relative to `self`. pub(crate) fn variant_star_import( &mut self, + handler: &Handler, src: &Path, dst: &Path, engines: &Engines, enum_name: &Ident, is_src_absolute: bool, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - - check!( - self.check_module_privacy(src, dst), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result<(), ErrorEmitted> { + self.check_module_privacy(handler, src, dst)?; let decl_engine = engines.de(); - let src_ns = check!( - self.check_submodule(src), - return err(warnings, errors), - warnings, - errors - ); + let src_ns = self.check_submodule(handler, src)?; match src_ns.symbols.get(enum_name).cloned() { Some(decl) => { if !decl.visibility(decl_engine).is_public() && !is_ancestor(src, dst) { - errors.push(CompileError::ImportPrivateSymbol { + handler.emit_err(CompileError::ImportPrivateSymbol { name: enum_name.clone(), span: enum_name.span(), }); @@ -668,49 +616,44 @@ impl Module { ); } } else { - errors.push(CompileError::Internal( + return Err(handler.emit_err(CompileError::Internal( "Attempting to import variants of something that isn't an enum", enum_name.span(), - )); - return err(warnings, errors); + ))); } } None => { - errors.push(CompileError::SymbolNotFound { + return Err(handler.emit_err(CompileError::SymbolNotFound { name: enum_name.clone(), span: enum_name.span(), - }); - return err(warnings, errors); + })); } }; - ok((), warnings, errors) + Ok(()) } - fn check_module_privacy(&self, src: &Path, dst: &Path) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - + fn check_module_privacy( + &self, + handler: &Handler, + src: &Path, + dst: &Path, + ) -> Result<(), ErrorEmitted> { // you are always allowed to access your ancestor's symbols if !is_ancestor(src, dst) { // we don't check the first prefix because direct children are always accessible for prefix in iter_prefixes(src).skip(1) { - let module = check!( - self.check_submodule(prefix), - return err(warnings, errors), - warnings, - errors - ); + let module = self.check_submodule(handler, prefix)?; if module.visibility.is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); - errors.push(CompileError::ImportPrivateModule { + handler.emit_err(CompileError::ImportPrivateModule { span: prefix_last.span(), name: prefix_last, }); } } } - ok((), warnings, errors) + Ok(()) } } diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index e7181f52ad1..7995a90c54b 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -1,15 +1,17 @@ use crate::{ decl_engine::{DeclRefConstant, DeclRefFunction}, engine_threading::*, - error::*, language::{ty, CallPath, Visibility}, type_system::*, - CompileResult, Ident, + Ident, }; use super::{module::Module, root::Root, submodule_namespace::SubmoduleNamespace, Path, PathBuf}; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{span::Span, Spanned}; use std::collections::{HashMap, VecDeque}; @@ -90,38 +92,54 @@ impl Namespace { } /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. - pub(crate) fn resolve_symbol(&self, symbol: &Ident) -> CompileResult<&ty::TyDecl> { - self.root.resolve_symbol(&self.mod_path, symbol) + pub(crate) fn resolve_symbol( + &self, + handler: &Handler, + symbol: &Ident, + ) -> Result<&ty::TyDecl, ErrorEmitted> { + self.root.resolve_symbol(handler, &self.mod_path, symbol) } /// Short-hand for calling [Root::resolve_call_path] on `root` with the `mod_path`. - pub(crate) fn resolve_call_path(&self, call_path: &CallPath) -> CompileResult<&ty::TyDecl> { - self.root.resolve_call_path(&self.mod_path, call_path) + pub(crate) fn resolve_call_path( + &self, + handler: &Handler, + call_path: &CallPath, + ) -> Result<&ty::TyDecl, ErrorEmitted> { + self.root + .resolve_call_path(handler, &self.mod_path, call_path) } /// Short-hand for calling [Root::resolve_call_path_with_visibility_check] on `root` with the `mod_path`. pub(crate) fn resolve_call_path_with_visibility_check( &self, + handler: &Handler, engines: &Engines, call_path: &CallPath, - ) -> CompileResult<&ty::TyDecl> { - self.root - .resolve_call_path_with_visibility_check(engines, &self.mod_path, call_path) + ) -> Result<&ty::TyDecl, ErrorEmitted> { + self.root.resolve_call_path_with_visibility_check( + handler, + engines, + &self.mod_path, + call_path, + ) } /// Short-hand for calling [Root::resolve_type_with_self] on `root` with the `mod_path`. #[allow(clippy::too_many_arguments)] // TODO: remove lint bypass once private modules are no longer experimental pub(crate) fn resolve_type_with_self( &mut self, + handler: &Handler, engines: &Engines, type_id: TypeId, self_type: TypeId, span: &Span, enforce_type_arguments: EnforceTypeArguments, type_info_prefix: Option<&Path>, - ) -> CompileResult { + ) -> Result { let mod_path = self.mod_path.clone(); engines.te().resolve_with_self( + handler, engines, type_id, self_type, @@ -136,13 +154,15 @@ impl Namespace { /// Short-hand for calling [Root::resolve_type_without_self] on `root` and with the `mod_path`. pub(crate) fn resolve_type_without_self( &mut self, + handler: &Handler, engines: &Engines, type_id: TypeId, span: &Span, type_info_prefix: Option<&Path>, - ) -> CompileResult { + ) -> Result { let mod_path = self.mod_path.clone(); engines.te().resolve( + handler, engines, type_id, span, @@ -157,15 +177,13 @@ impl Namespace { /// resolve it), find items matching in the namespace. pub(crate) fn find_items_for_type( &mut self, + handler: &Handler, mut type_id: TypeId, item_prefix: &Path, item_name: &Ident, self_type: TypeId, engines: &Engines, - ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result, ErrorEmitted> { let type_engine = engines.te(); let _decl_engine = engines.de(); @@ -173,16 +191,12 @@ impl Namespace { // we want to return the error case without creating a new error // message. if let TypeInfo::ErrorRecovery = type_engine.get(type_id) { - return err(warnings, errors); + // FIXME: find a better way to handle error recovery + return Err(ErrorEmitted); } // grab the local module - let local_module = check!( - self.root().check_submodule(&self.mod_path), - return err(warnings, errors), - warnings, - errors - ); + let local_module = self.root().check_submodule(handler, &self.mod_path)?; // grab the local items from the local module let local_items = local_module.get_items_for_type(engines, type_id); @@ -190,8 +204,9 @@ impl Namespace { type_id.replace_self_type(engines, self_type); // resolve the type - let type_id = check!( - type_engine.resolve( + let type_id = type_engine + .resolve( + handler, engines, type_id, &item_name.span(), @@ -199,19 +214,11 @@ impl Namespace { None, self, item_prefix, - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); // grab the module where the type itself is declared - let type_module = check!( - self.root().check_submodule(item_prefix), - return err(warnings, errors), - warnings, - errors - ); + let type_module = self.root().check_submodule(handler, item_prefix)?; // grab the items from where the type is declared let mut type_items = type_module.get_items_for_type(engines, type_id); @@ -236,7 +243,7 @@ impl Namespace { } } - ok(matching_item_decl_refs, warnings, errors) + Ok(matching_item_decl_refs) } /// Given a name and a type (plus a `self_type` to potentially @@ -249,6 +256,7 @@ impl Namespace { #[allow(clippy::too_many_arguments)] // TODO: remove lint bypass once private modules are no longer experimental pub(crate) fn find_method_for_type( &mut self, + handler: &Handler, type_id: TypeId, method_prefix: &Path, method_name: &Ident, @@ -258,10 +266,7 @@ impl Namespace { as_trait: Option, engines: &Engines, try_inserting_trait_impl_on_failure: bool, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let decl_engine = engines.de(); let type_engine = engines.te(); @@ -270,20 +275,17 @@ impl Namespace { // default numeric types to u64 if type_engine.contains_numeric(decl_engine, type_id) { - check!( - type_engine.decay_numeric(engines, type_id, &method_name.span()), - return err(warnings, errors), - warnings, - errors - ); + type_engine.decay_numeric(handler, engines, type_id, &method_name.span())?; } - let matching_item_decl_refs = check!( - self.find_items_for_type(type_id, method_prefix, method_name, self_type, engines,), - return err(warnings, errors), - warnings, - errors - ); + let matching_item_decl_refs = self.find_items_for_type( + handler, + type_id, + method_prefix, + method_name, + self_type, + engines, + )?; let matching_method_decl_refs = matching_item_decl_refs .into_iter() @@ -342,22 +344,12 @@ impl Namespace { .iter() .zip(trait_decl.trait_type_arguments.clone()) { - let p1_type_id = check!( - self.resolve_type_without_self( - engines, p1.type_id, &p1.span, None - ), - return err(warnings, errors), - warnings, - errors - ); - let p2_type_id = check!( - self.resolve_type_without_self( - engines, p2.type_id, &p2.span, None - ), - return err(warnings, errors), - warnings, - errors - ); + let p1_type_id = self.resolve_type_without_self( + handler, engines, p1.type_id, &p1.span, None, + )?; + let p2_type_id = self.resolve_type_without_self( + handler, engines, p2.type_id, &p2.span, None, + )?; if !eq_check.check(p1_type_id, p2_type_id) { params_equal = false; break; @@ -434,13 +426,14 @@ impl Namespace { .collect::>(); // Sort so the output of the error is always the same. trait_strings.sort(); - errors.push(CompileError::MultipleApplicableItemsInScope { - method_name: method_name.as_str().to_string(), - type_name: engines.help_out(type_id).to_string(), - as_traits: trait_strings, - span: method_name.span(), - }); - return err(warnings, errors); + return Err(handler.emit_err( + CompileError::MultipleApplicableItemsInScope { + method_name: method_name.as_str().to_string(), + type_name: engines.help_out(type_id).to_string(), + as_traits: trait_strings, + span: method_name.span(), + }, + )); } } else if qualified_call_path.is_some() { // When we use a qualified path the expected method should be in trait_methods. @@ -456,7 +449,7 @@ impl Namespace { }; if let Some(method_decl_ref) = matching_method_decl_ref { - return ok(method_decl_ref, warnings, errors); + return Ok(method_decl_ref); } if !args_buf @@ -472,6 +465,7 @@ impl Namespace { self.insert_trait_implementation_for_type(engines, type_id); return self.find_method_for_type( + handler, type_id, method_prefix, method_name, @@ -488,13 +482,13 @@ impl Namespace { } else { engines.help_out(type_id).to_string() }; - errors.push(CompileError::MethodNotFound { + handler.emit_err(CompileError::MethodNotFound { method_name: method_name.clone(), type_name, span: method_name.span(), }); } - err(warnings, errors) + Err(ErrorEmitted) } /// Given a name and a type (plus a `self_type` to potentially @@ -506,20 +500,20 @@ impl Namespace { /// found. pub(crate) fn find_constant_for_type( &mut self, + handler: &Handler, type_id: TypeId, item_name: &Ident, self_type: TypeId, engines: &Engines, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - - let matching_item_decl_refs = check!( - self.find_items_for_type(type_id, &Vec::::new(), item_name, self_type, engines,), - return err(warnings, errors), - warnings, - errors - ); + ) -> Result { + let matching_item_decl_refs = self.find_items_for_type( + handler, + type_id, + &Vec::::new(), + item_name, + self_type, + engines, + )?; let matching_constant_decl_refs = matching_item_decl_refs .into_iter() @@ -530,71 +524,91 @@ impl Namespace { .collect::>(); if let Some(constant_decl_ref) = matching_constant_decl_refs.first() { - ok(constant_decl_ref.clone(), warnings, errors) + Ok(constant_decl_ref.clone()) } else { - err(warnings, errors) + Err(ErrorEmitted) } } /// Short-hand for performing a [Module::star_import] with `mod_path` as the destination. pub(crate) fn star_import( &mut self, + handler: &Handler, src: &Path, engines: &Engines, is_absolute: bool, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { self.root - .star_import(src, &self.mod_path, engines, is_absolute) + .star_import(handler, src, &self.mod_path, engines, is_absolute) } /// Short-hand for performing a [Module::variant_star_import] with `mod_path` as the destination. pub(crate) fn variant_star_import( &mut self, + handler: &Handler, src: &Path, engines: &Engines, enum_name: &Ident, is_absolute: bool, - ) -> CompileResult<()> { - self.root - .variant_star_import(src, &self.mod_path, engines, enum_name, is_absolute) + ) -> Result<(), ErrorEmitted> { + self.root.variant_star_import( + handler, + src, + &self.mod_path, + engines, + enum_name, + is_absolute, + ) } /// Short-hand for performing a [Module::self_import] with `mod_path` as the destination. pub(crate) fn self_import( &mut self, + handler: &Handler, engines: &Engines, src: &Path, alias: Option, is_absolute: bool, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { self.root - .self_import(engines, src, &self.mod_path, alias, is_absolute) + .self_import(handler, engines, src, &self.mod_path, alias, is_absolute) } /// Short-hand for performing a [Module::item_import] with `mod_path` as the destination. pub(crate) fn item_import( &mut self, + handler: &Handler, engines: &Engines, src: &Path, item: &Ident, alias: Option, is_absolute: bool, - ) -> CompileResult<()> { - self.root - .item_import(engines, src, item, &self.mod_path, alias, is_absolute) + ) -> Result<(), ErrorEmitted> { + self.root.item_import( + handler, + engines, + src, + item, + &self.mod_path, + alias, + is_absolute, + ) } /// Short-hand for performing a [Module::variant_import] with `mod_path` as the destination. + #[allow(clippy::too_many_arguments)] pub(crate) fn variant_import( &mut self, + handler: &Handler, engines: &Engines, src: &Path, enum_name: &Ident, variant_name: &Ident, alias: Option, is_absolute: bool, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { self.root.variant_import( + handler, engines, src, enum_name, @@ -639,6 +653,7 @@ impl Namespace { #[allow(clippy::too_many_arguments)] pub(crate) fn insert_trait_implementation( &mut self, + handler: &Handler, trait_name: CallPath, trait_type_args: Vec, type_id: TypeId, @@ -647,12 +662,13 @@ impl Namespace { trait_decl_span: Option, is_impl_self: bool, engines: &Engines, - ) -> CompileResult<()> { + ) -> Result<(), ErrorEmitted> { // Use trait name with full path, improves consistency between // this inserting and getting in `get_methods_for_type_and_trait_name`. let full_trait_name = trait_name.to_fullpath(self); self.implemented_traits.insert( + handler, full_trait_name, trait_type_args, type_id, diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index a05c1023008..7c012dbe953 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -1,11 +1,13 @@ -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::Spanned; use sway_utils::iter_prefixes; use crate::{ - error::*, language::{ty, CallPath}, - CompileResult, Engines, Ident, + Engines, Ident, }; use super::{module::Module, namespace::Namespace, Path}; @@ -30,15 +32,16 @@ impl Root { /// then calling `resolve_symbol` with the resulting path and call_path's suffix. pub(crate) fn resolve_call_path( &self, + handler: &Handler, mod_path: &Path, call_path: &CallPath, - ) -> CompileResult<&ty::TyDecl> { + ) -> Result<&ty::TyDecl, ErrorEmitted> { let symbol_path: Vec<_> = mod_path .iter() .chain(&call_path.prefixes) .cloned() .collect(); - self.resolve_symbol(&symbol_path, &call_path.suffix) + self.resolve_symbol(handler, &symbol_path, &call_path.suffix) } /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. @@ -51,37 +54,25 @@ impl Root { /// and the symbol's own visibility pub(crate) fn resolve_call_path_with_visibility_check( &self, + handler: &Handler, engines: &Engines, mod_path: &Path, call_path: &CallPath, - ) -> CompileResult<&ty::TyDecl> { - let mut warnings = vec![]; - let mut errors = vec![]; - - let decl = check!( - self.resolve_call_path(mod_path, call_path), - return err(warnings, errors), - warnings, - errors, - ); + ) -> Result<&ty::TyDecl, ErrorEmitted> { + let decl = self.resolve_call_path(handler, mod_path, call_path)?; // In case there are no prefixes we don't need to check visibility if call_path.prefixes.is_empty() { - return ok(decl, warnings, errors); + return Ok(decl); } // check the visibility of the call path elements // we don't check the first prefix because direct children are always accessible for prefix in iter_prefixes(&call_path.prefixes).skip(1) { - let module = check!( - self.check_submodule(prefix), - return err(warnings, errors), - warnings, - errors - ); + let module = self.check_submodule(handler, prefix)?; if module.visibility.is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); - errors.push(CompileError::ImportPrivateModule { + handler.emit_err(CompileError::ImportPrivateModule { span: prefix_last.span(), name: prefix_last, }); @@ -90,13 +81,13 @@ impl Root { // check the visibility of the symbol itself if !decl.visibility(engines.de()).is_public() { - errors.push(CompileError::ImportPrivateSymbol { + handler.emit_err(CompileError::ImportPrivateSymbol { name: call_path.suffix.clone(), span: call_path.suffix.span(), }); } - ok(decl, warnings, errors) + Ok(decl) } /// Given a path to a module and the identifier of a symbol within that module, resolve its @@ -106,23 +97,24 @@ impl Root { /// imports until we find the original declaration. pub(crate) fn resolve_symbol( &self, + handler: &Handler, mod_path: &Path, symbol: &Ident, - ) -> CompileResult<&ty::TyDecl> { - self.check_submodule(mod_path).flat_map(|module| { + ) -> Result<&ty::TyDecl, ErrorEmitted> { + self.check_submodule(handler, mod_path).and_then(|module| { let true_symbol = self[mod_path] .use_aliases .get(symbol.as_str()) .unwrap_or(symbol); match module.use_synonyms.get(symbol) { - Some((_, _, decl @ ty::TyDecl::EnumVariantDecl { .. }, _)) => { - ok(decl, vec![], vec![]) - } + Some((_, _, decl @ ty::TyDecl::EnumVariantDecl { .. }, _)) => Ok(decl), Some((src_path, _, _, _)) if mod_path != src_path => { // TODO: check that the symbol import is public? - self.resolve_symbol(src_path, true_symbol) + self.resolve_symbol(handler, src_path, true_symbol) } - _ => CompileResult::from(module.check_symbol(true_symbol)), + _ => module + .check_symbol(true_symbol) + .map_err(|e| handler.emit_err(e)), } }) } diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 6ad3bb4ae70..f0ce7e1234c 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -3,13 +3,15 @@ use std::{ collections::{BTreeMap, BTreeSet}, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Ident, Span, Spanned}; use crate::{ decl_engine::{DeclEngineGet, DeclEngineInsert}, engine_threading::*, - error::*, language::{ ty::{self, TyImplItem}, CallPath, @@ -108,6 +110,7 @@ impl TraitMap { #[allow(clippy::too_many_arguments)] pub(crate) fn insert( &mut self, + handler: &Handler, trait_name: CallPath, trait_type_args: Vec, type_id: TypeId, @@ -116,13 +119,12 @@ impl TraitMap { trait_decl_span: Option, is_impl_self: bool, engines: &Engines, - ) -> CompileResult<()> { - let warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(), ErrorEmitted> { let type_engine = engines.te(); let _decl_engine = engines.de(); + let mut error_emitted = None; + let mut trait_items: TraitItems = im::HashMap::new(); for item in items.iter() { match item { @@ -132,10 +134,11 @@ impl TraitMap { .is_some() { // duplicate method name - errors.push(CompileError::MultipleDefinitionsOfName { - name: decl_ref.name().clone(), - span: decl_ref.span(), - }); + error_emitted = + Some(handler.emit_err(CompileError::MultipleDefinitionsOfName { + name: decl_ref.name().clone(), + span: decl_ref.span(), + })); } } TyImplItem::Constant(decl_ref) => { @@ -211,32 +214,40 @@ impl TraitMap { ) } ); - errors.push(CompileError::ConflictingImplsForTraitAndType { - trait_name: trait_name_str, - type_implementing_for: engines.help_out(type_id).to_string(), - second_impl_span: impl_span.clone(), - }); + error_emitted = Some(handler.emit_err( + CompileError::ConflictingImplsForTraitAndType { + trait_name: trait_name_str, + type_implementing_for: engines.help_out(type_id).to_string(), + second_impl_span: impl_span.clone(), + }, + )); } else if types_are_subset && (traits_are_subset || is_impl_self) { for (name, item) in trait_items.iter() { match item { ty::TyTraitItem::Fn(decl_ref) => { if map_trait_items.get(name).is_some() { - errors.push(CompileError::DuplicateDeclDefinedForType { - decl_kind: "method".into(), - decl_name: decl_ref.name().to_string(), - type_implementing_for: engines.help_out(type_id).to_string(), - span: decl_ref.name().span(), - }); + error_emitted = Some(handler.emit_err( + CompileError::DuplicateDeclDefinedForType { + decl_kind: "method".into(), + decl_name: decl_ref.name().to_string(), + type_implementing_for: + engines.help_out(type_id).to_string(), + span: decl_ref.name().span(), + }, + )); } } ty::TyTraitItem::Constant(decl_ref) => { if map_trait_items.get(name).is_some() { - errors.push(CompileError::DuplicateDeclDefinedForType { - decl_kind: "constant".into(), - decl_name: decl_ref.name().to_string(), - type_implementing_for: engines.help_out(type_id).to_string(), - span: decl_ref.name().span(), - }); + error_emitted = Some(handler.emit_err( + CompileError::DuplicateDeclDefinedForType { + decl_kind: "constant".into(), + decl_name: decl_ref.name().to_string(), + type_implementing_for: + engines.help_out(type_id).to_string(), + span: decl_ref.name().span(), + }, + )); } } } @@ -262,10 +273,10 @@ impl TraitMap { engines, ); - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } @@ -864,25 +875,18 @@ impl TraitMap { /// Checks to see if the trait constraints are satisfied for a given type. pub(crate) fn check_if_trait_constraints_are_satisfied_for_type( &self, + handler: &Handler, type_id: TypeId, constraints: &[TraitConstraint], access_span: &Span, engines: &Engines, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(), ErrorEmitted> { let type_engine = engines.te(); let _decl_engine = engines.de(); let unify_check = UnifyCheck::non_dynamic_equality(engines); // resolving trait constraits require a concrete type, we need to default numeric to u64 - check!( - type_engine.decay_numeric(engines, type_id, access_span), - return err(warnings, errors), - warnings, - errors - ); + type_engine.decay_numeric(handler, engines, type_id, access_span)?; let all_impld_traits: BTreeMap = self .trait_impls @@ -947,19 +951,20 @@ impl TraitMap { let relevant_impld_traits_names: BTreeSet = relevant_impld_traits.keys().cloned().collect(); + let mut error_emitted = None; for trait_name in required_traits_names.difference(&relevant_impld_traits_names) { // TODO: use a better span - errors.push(CompileError::TraitConstraintNotSatisfied { + error_emitted = Some(handler.emit_err(CompileError::TraitConstraintNotSatisfied { ty: engines.help_out(type_id).to_string(), trait_name: trait_name.to_string(), span: access_span.clone(), - }); + })); } - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } } diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index a025a2a5f20..5197c261689 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -2,13 +2,13 @@ use std::collections::{HashMap, HashSet}; use std::iter::FromIterator; use crate::{ - error::*, language::{parsed::*, CallPath}, type_system::*, Engines, }; use sway_error::error::CompileError; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::integer_bits::IntegerBits; use sway_types::Spanned; use sway_types::{ident::Ident, span::Span}; @@ -18,9 +18,10 @@ use sway_types::{ident::Ident, span::Span}; /// dependencies breaking. pub(crate) fn order_ast_nodes_by_dependency( + handler: &Handler, engines: &Engines, nodes: Vec, -) -> CompileResult> { +) -> Result, ErrorEmitted> { let type_engine = engines.te(); let decl_dependencies = DependencyMap::from_iter( @@ -35,20 +36,22 @@ pub(crate) fn order_ast_nodes_by_dependency( // Because we're pulling these errors out of a HashMap they'll probably be in a funny // order. Here we'll sort them by span start. errors.sort_by_key(|err| err.span().start()); - err(Vec::new(), errors) + + let error_emitted = errors + .into_iter() + .fold(None, |_acc, err| Some(handler.emit_err(err))) + .unwrap(); + + Err(error_emitted) } else { // Reorder the parsed AstNodes based on dependency. Includes first, then uses, then // reordered declarations, then anything else. To keep the list stable and simple we can // use a basic insertion sort. - ok( - nodes - .into_iter() - .fold(Vec::::new(), |ordered, node| { - insert_into_ordered_nodes(type_engine, &decl_dependencies, ordered, node) - }), - Vec::new(), - Vec::new(), - ) + Ok(nodes + .into_iter() + .fold(Vec::::new(), |ordered, node| { + insert_into_ordered_nodes(type_engine, &decl_dependencies, ordered, node) + })) } } diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index b384a54255c..bb9bf3131db 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -1,5 +1,4 @@ use crate::{ - error::*, language::{parsed::ParseProgram, ty}, metadata::MetadataManager, semantic_analysis::{ @@ -8,6 +7,7 @@ use crate::{ }, Engines, }; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_ir::{Context, Module}; impl ty::TyProgram { @@ -16,18 +16,18 @@ impl ty::TyProgram { /// The given `initial_namespace` acts as an initial state for each module within this program. /// It should contain a submodule for each library package dependency. pub fn type_check( + handler: &Handler, engines: &Engines, parsed: &ParseProgram, initial_namespace: namespace::Module, package_name: &str, - ) -> CompileResult { + ) -> Result { let mut namespace = Namespace::init_root(initial_namespace); let ctx = TypeCheckContext::from_root(&mut namespace, engines).with_kind(parsed.kind.clone()); let ParseProgram { root, kind } = parsed; - let mod_res = ty::TyModule::type_check(ctx, root); - mod_res.flat_map(|root| { - let res = Self::validate_root(engines, &root, kind.clone(), package_name); + ty::TyModule::type_check(handler, ctx, root).and_then(|root| { + let res = Self::validate_root(handler, engines, &root, kind.clone(), package_name); res.map(|(kind, declarations, configurables)| Self { kind, root, @@ -42,13 +42,12 @@ impl ty::TyProgram { pub(crate) fn get_typed_program_with_initialized_storage_slots( self, + handler: &Handler, engines: &Engines, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result { let decl_engine = engines.de(); match &self.kind { ty::TyProgramKind::Contract { .. } => { @@ -65,42 +64,27 @@ impl ty::TyProgram { .. })) => { let decl = decl_engine.get_storage(decl_id); - let mut storage_slots = check!( - decl.get_initialized_storage_slots(engines, context, md_mgr, module,), - return err(warnings, errors), - warnings, - errors, - ); + let mut storage_slots = decl.get_initialized_storage_slots( + handler, engines, context, md_mgr, module, + )?; // Sort the slots to standardize the output. Not strictly required by the // spec. storage_slots.sort(); - ok( - Self { - storage_slots, - ..self - }, - warnings, - errors, - ) - } - _ => ok( - Self { - storage_slots: vec![], + Ok(Self { + storage_slots, ..self - }, - warnings, - errors, - ), + }) + } + _ => Ok(Self { + storage_slots: vec![], + ..self + }), } } - _ => ok( - Self { - storage_slots: vec![], - ..self - }, - warnings, - errors, - ), + _ => Ok(Self { + storage_slots: vec![], + ..self + }), } } } diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index fd48f2262af..4d4c88d6306 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -9,9 +9,12 @@ use crate::{ type_system::{ EnforceTypeArguments, MonomorphizeHelper, SubstTypes, TypeArgument, TypeId, TypeInfo, }, - CompileResult, CompileWarning, + CompileWarning, +}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, }; -use sway_error::error::CompileError; use sway_types::{span::Span, Ident}; /// Contextual state tracked and accumulated throughout type-checking. @@ -257,16 +260,18 @@ impl<'a> TypeCheckContext<'a> { /// Short-hand for calling the `monomorphize` function in the type engine pub(crate) fn monomorphize( &mut self, + handler: &Handler, value: &mut T, type_arguments: &mut [TypeArgument], enforce_type_arguments: EnforceTypeArguments, call_site_span: &Span, - ) -> CompileResult<()> + ) -> Result<(), ErrorEmitted> where T: MonomorphizeHelper + SubstTypes, { let mod_path = self.namespace.mod_path.clone(); self.engines.te().monomorphize( + handler, self.engines(), value, type_arguments, @@ -281,12 +286,14 @@ impl<'a> TypeCheckContext<'a> { /// the `TypeCheckContext`. pub(crate) fn resolve_type_with_self( &mut self, + handler: &Handler, type_id: TypeId, span: &Span, enforce_type_args: EnforceTypeArguments, type_info_prefix: Option<&Path>, - ) -> CompileResult { + ) -> Result { self.namespace.resolve_type_with_self( + handler, self.engines(), type_id, self.self_type, @@ -299,12 +306,18 @@ impl<'a> TypeCheckContext<'a> { /// Short-hand for calling [Namespace::resolve_type_without_self] pub(crate) fn resolve_type_without_self( &mut self, + handler: &Handler, type_id: TypeId, span: &Span, type_info_prefix: Option<&Path>, - ) -> CompileResult { - self.namespace - .resolve_type_without_self(self.engines(), type_id, span, type_info_prefix) + ) -> Result { + self.namespace.resolve_type_without_self( + handler, + self.engines(), + type_id, + span, + type_info_prefix, + ) } /// Short-hand around `type_system::unify_with_self`, where the `TypeCheckContext` provides the @@ -327,9 +340,14 @@ impl<'a> TypeCheckContext<'a> { /// Short-hand for calling [Namespace::insert_symbol] with the `const_shadowing_mode` provided by /// the `TypeCheckContext`. - pub(crate) fn insert_symbol(&mut self, name: Ident, item: TyDecl) -> CompileResult<()> { + pub(crate) fn insert_symbol( + &mut self, + handler: &Handler, + name: Ident, + item: TyDecl, + ) -> Result<(), ErrorEmitted> { self.namespace - .insert_symbol(name, item, self.const_shadowing_mode) + .insert_symbol(handler, name, item, self.const_shadowing_mode) } /// Get the engines needed for engine threading. diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 5c0c2b72f0d..54a3b830fb9 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -1,9 +1,9 @@ +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Span, Spanned}; use crate::{ decl_engine::*, engine_threading::*, - error::*, language::{ty, CallPath}, semantic_analysis::TypeCheckContext, type_system::priv_prelude::*, @@ -160,11 +160,9 @@ impl TypeBinding { impl TypeBinding> { pub(crate) fn type_check_with_type_info( &self, + handler: &Handler, ctx: &mut TypeCheckContext, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -173,35 +171,29 @@ impl TypeBinding> { // find the module that the symbol is in let type_info_prefix = ctx.namespace.find_module_path(&self.inner.prefixes); - check!( - ctx.namespace.root().check_submodule(&type_info_prefix), - return err(warnings, errors), - warnings, - errors - ); + ctx.namespace + .root() + .check_submodule(handler, &type_info_prefix)?; // create the type info object - let type_info = check!( - type_info.apply_type_arguments(self.type_arguments.to_vec(), &type_info_span), - return err(warnings, errors), - warnings, - errors - ); + let type_info = type_info.apply_type_arguments( + handler, + self.type_arguments.to_vec(), + &type_info_span, + )?; // resolve the type of the type info object - let type_id = check!( - ctx.resolve_type_with_self( + let type_id = ctx + .resolve_type_with_self( + handler, type_engine.insert(engines, type_info), &type_info_span, EnforceTypeArguments::No, - Some(&type_info_prefix) - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + Some(&type_info_prefix), + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); - ok(type_id, warnings, errors) + Ok(type_id) } } @@ -217,71 +209,58 @@ impl TypeBinding { pub(crate) trait TypeCheckTypeBinding { fn type_check( &mut self, + handler: &Handler, ctx: TypeCheckContext, - ) -> CompileResult<(DeclRef>, Option, Option)>; + ) -> Result<(DeclRef>, Option, Option), ErrorEmitted>; } impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, + handler: &Handler, mut ctx: TypeCheckContext, - ) -> CompileResult<( - DeclRef>, - Option, - Option, - )> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result< + ( + DeclRef>, + Option, + Option, + ), + ErrorEmitted, + > { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = check!( - ctx.namespace - .resolve_call_path_with_visibility_check(engines, &self.inner) - .cloned(), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = ctx + .namespace + .resolve_call_path_with_visibility_check(handler, engines, &self.inner) + .cloned()?; // Check to see if this is a fn declaration. - let fn_ref = check!( - unknown_decl.to_fn_ref(), - return err(warnings, errors), - warnings, - errors - ); + let fn_ref = unknown_decl.to_fn_ref(handler)?; // Get a new copy from the declaration engine. let mut new_copy = decl_engine.get_function(fn_ref.id()); match self.type_arguments { // Monomorphize the copy, in place. TypeArgs::Regular(_) => { - check!( - ctx.monomorphize( - &mut new_copy, - self.type_arguments.to_vec_mut(), - EnforceTypeArguments::No, - &self.span - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut new_copy, + self.type_arguments.to_vec_mut(), + EnforceTypeArguments::No, + &self.span, + )?; } TypeArgs::Prefix(_) => { // Resolve the type arguments without monomorphizing. for type_argument in self.type_arguments.to_vec_mut().iter_mut() { - check!( - ctx.resolve_type_with_self( - type_argument.type_id, - &type_argument.span, - EnforceTypeArguments::Yes, - None - ), - type_engine.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors, - ); + ctx.resolve_type_with_self( + handler, + type_argument.type_id, + &type_argument.span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); } } } @@ -291,87 +270,74 @@ impl TypeCheckTypeBinding for TypeBinding { .de() .insert(new_copy) .with_parent(ctx.engines.de(), fn_ref.id().into()); - ok((new_fn_ref, None, None), warnings, errors) + Ok((new_fn_ref, None, None)) } } impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, + handler: &Handler, mut ctx: TypeCheckContext, - ) -> CompileResult<( - DeclRef>, - Option, - Option, - )> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result< + ( + DeclRef>, + Option, + Option, + ), + ErrorEmitted, + > { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = check!( - ctx.namespace - .resolve_call_path_with_visibility_check(engines, &self.inner,) - .cloned(), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = ctx + .namespace + .resolve_call_path_with_visibility_check(handler, engines, &self.inner) + .cloned()?; // Check to see if this is a struct declaration. - let struct_ref = check!( - unknown_decl.to_struct_ref(engines), - return err(warnings, errors), - warnings, - errors - ); + let struct_ref = unknown_decl.to_struct_ref(handler, engines)?; // Get a new copy from the declaration engine. let mut new_copy = decl_engine.get_struct(struct_ref.id()); // Monomorphize the copy, in place. - check!( - ctx.monomorphize( - &mut new_copy, - self.type_arguments.to_vec_mut(), - EnforceTypeArguments::No, - &self.span - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut new_copy, + self.type_arguments.to_vec_mut(), + EnforceTypeArguments::No, + &self.span, + )?; // Insert the new copy into the declaration engine. let new_struct_ref = ctx.engines.de().insert(new_copy); // Take any trait items that apply to the old type and copy them to the new type. let type_id = type_engine.insert(engines, TypeInfo::Struct(new_struct_ref.clone())); ctx.namespace .insert_trait_implementation_for_type(engines, type_id); - ok((new_struct_ref, Some(type_id), None), warnings, errors) + Ok((new_struct_ref, Some(type_id), None)) } } impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, + handler: &Handler, mut ctx: TypeCheckContext, - ) -> CompileResult<( - DeclRef>, - Option, - Option, - )> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result< + ( + DeclRef>, + Option, + Option, + ), + ErrorEmitted, + > { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = check!( - ctx.namespace - .resolve_call_path_with_visibility_check(engines, &self.inner,) - .cloned(), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = ctx + .namespace + .resolve_call_path_with_visibility_check(handler, engines, &self.inner) + .cloned()?; // Get a new copy from the declaration engine. let mut new_copy = if let ty::TyDecl::EnumVariantDecl(ty::EnumVariantDecl { @@ -382,73 +348,52 @@ impl TypeCheckTypeBinding for TypeBinding { decl_engine.get_enum(enum_ref.id()) } else { // Check to see if this is a enum declaration. - let enum_ref = check!( - unknown_decl.to_enum_ref(engines), - return err(warnings, errors), - warnings, - errors - ); + let enum_ref = unknown_decl.to_enum_ref(handler, engines)?; decl_engine.get_enum(enum_ref.id()) }; // Monomorphize the copy, in place. - check!( - ctx.monomorphize( - &mut new_copy, - self.type_arguments.to_vec_mut(), - EnforceTypeArguments::No, - &self.span - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut new_copy, + self.type_arguments.to_vec_mut(), + EnforceTypeArguments::No, + &self.span, + )?; // Insert the new copy into the declaration engine. let new_enum_ref = ctx.engines.de().insert(new_copy); // Take any trait items that apply to the old type and copy them to the new type. let type_id = type_engine.insert(engines, TypeInfo::Enum(new_enum_ref.clone())); ctx.namespace .insert_trait_implementation_for_type(engines, type_id); - ok( - (new_enum_ref, Some(type_id), Some(unknown_decl)), - warnings, - errors, - ) + Ok((new_enum_ref, Some(type_id), Some(unknown_decl))) } } impl TypeCheckTypeBinding for TypeBinding { fn type_check( &mut self, + handler: &Handler, ctx: TypeCheckContext, - ) -> CompileResult<( - DeclRef>, - Option, - Option, - )> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result< + ( + DeclRef>, + Option, + Option, + ), + ErrorEmitted, + > { let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = check!( - ctx.namespace - .resolve_call_path_with_visibility_check(engines, &self.inner,) - .cloned(), - return err(warnings, errors), - warnings, - errors - ); + let unknown_decl = ctx + .namespace + .resolve_call_path_with_visibility_check(handler, engines, &self.inner) + .cloned()?; // Check to see if this is a const declaration. - let const_ref = check!( - unknown_decl.to_const_ref(), - return err(warnings, errors), - warnings, - errors - ); + let const_ref = unknown_decl.to_const_ref(handler)?; - ok((const_ref, None, None), warnings, errors) + Ok((const_ref, None, None)) } } diff --git a/sway-core/src/type_system/ast_elements/trait_constraint.rs b/sway-core/src/type_system/ast_elements/trait_constraint.rs index d41e8a33928..ba878feebee 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -3,12 +3,14 @@ use std::{ hash::{Hash, Hasher}, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{Span, Spanned}; use crate::{ engine_threading::*, - error::*, language::{parsed::Supertrait, ty, CallPath}, semantic_analysis::{ declaration::{insert_supertraits_into_namespace, SupertraitOf}, @@ -16,7 +18,6 @@ use crate::{ }, type_system::priv_prelude::*, types::*, - CompileResult, }; #[derive(Debug, Clone)] @@ -88,42 +89,46 @@ impl From<&Supertrait> for TraitConstraint { impl CollectTypesMetadata for TraitConstraint { fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result, ErrorEmitted> { let mut res = vec![]; + let mut error_emitted = None; for type_arg in self.type_arguments.iter() { - res.extend(check!( - type_arg.type_id.collect_types_metadata(ctx), - continue, - warnings, - errors - )); + res.extend( + match type_arg.type_id.collect_types_metadata(handler, ctx) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }, + ); } - if errors.is_empty() { - ok(res, warnings, errors) + + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(res) } } } impl TraitConstraint { - pub(crate) fn type_check(&mut self, mut ctx: TypeCheckContext) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - + pub(crate) fn type_check( + &mut self, + handler: &Handler, + mut ctx: TypeCheckContext, + ) -> Result<(), ErrorEmitted> { // Right now we don't have the ability to support defining a type for a // trait constraint using a callpath directly, so we check to see if the // user has done this and we disallow it. if !self.trait_name.prefixes.is_empty() { - errors.push(CompileError::UnimplementedWithHelp( + return Err(handler.emit_err(CompileError::UnimplementedWithHelp( "Using module paths to define trait constraints is not supported yet.", "try importing the trait with a \"use\" statement instead", self.trait_name.span(), - )); - return err(warnings, errors); + ))); } // Right now we aren't supporting generic traits in trait constraints @@ -138,7 +143,7 @@ impl TraitConstraint { // // TODO: implement a fix for the above in a future PR if !self.type_arguments.is_empty() { - errors.push(CompileError::Unimplemented( + return Err(handler.emit_err(CompileError::Unimplemented( "Using generic traits in trait constraints is not supported yet.", Span::join_all( self.type_arguments @@ -146,37 +151,34 @@ impl TraitConstraint { .map(|x| x.span()) .collect::>(), ), - )); - return err(warnings, errors); + ))); } // Type check the type arguments. for type_argument in self.type_arguments.iter_mut() { - type_argument.type_id = check!( - ctx.resolve_type_without_self(type_argument.type_id, &type_argument.span, None), - ctx.engines - .te() - .insert(ctx.engines(), TypeInfo::ErrorRecovery), - warnings, - errors - ); + type_argument.type_id = ctx + .resolve_type_without_self( + handler, + type_argument.type_id, + &type_argument.span, + None, + ) + .unwrap_or_else(|_| { + ctx.engines + .te() + .insert(ctx.engines(), TypeInfo::ErrorRecovery) + }); } - if errors.is_empty() { - ok((), warnings, errors) - } else { - err(warnings, errors) - } + Ok(()) } pub(crate) fn insert_into_namespace( + handler: &Handler, mut ctx: TypeCheckContext, type_id: TypeId, trait_constraint: &TraitConstraint, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(), ErrorEmitted> { let decl_engine = ctx.engines.de(); let TraitConstraint { @@ -188,29 +190,26 @@ impl TraitConstraint { match ctx .namespace - .resolve_call_path(trait_name) - .ok(&mut warnings, &mut errors) + .resolve_call_path(handler, trait_name) + .ok() .cloned() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { let mut trait_decl = decl_engine.get_trait(&decl_id); // Monomorphize the trait declaration. - check!( - ctx.monomorphize( - &mut trait_decl, - &mut type_arguments, - EnforceTypeArguments::Yes, - &trait_name.span() - ), - return err(warnings, errors), - warnings, - errors - ); + ctx.monomorphize( + handler, + &mut trait_decl, + &mut type_arguments, + EnforceTypeArguments::Yes, + &trait_name.span(), + )?; // Insert the interface surface and methods from this trait into // the namespace. trait_decl.insert_interface_surface_and_items_into_namespace( + handler, ctx.by_ref(), trait_name, &type_arguments, @@ -219,27 +218,27 @@ impl TraitConstraint { // Recursively make the interface surfaces and methods of the // supertraits available to this trait. - check!( - insert_supertraits_into_namespace( - ctx.by_ref(), - type_id, - &trait_decl.supertraits, - &SupertraitOf::Trait - ), - return err(warnings, errors), - warnings, - errors - ); + insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + type_id, + &trait_decl.supertraits, + &SupertraitOf::Trait, + )?; + } + Some(ty::TyDecl::AbiDecl { .. }) => { + handler.emit_err(CompileError::AbiAsSupertrait { + span: trait_name.span(), + }); + } + _ => { + handler.emit_err(CompileError::TraitNotFound { + name: trait_name.to_string(), + span: trait_name.span(), + }); } - Some(ty::TyDecl::AbiDecl { .. }) => errors.push(CompileError::AbiAsSupertrait { - span: trait_name.span(), - }), - _ => errors.push(CompileError::TraitNotFound { - name: trait_name.to_string(), - span: trait_name.span(), - }), } - ok((), warnings, errors) + Ok(()) } } diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index 96b06550058..073c91a8964 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -1,13 +1,15 @@ use crate::{ decl_engine::*, engine_threading::*, - error::*, language::{ty, CallPath}, semantic_analysis::*, type_system::priv_prelude::*, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{ident::Ident, span::Span, Spanned}; use std::{ @@ -132,36 +134,40 @@ impl TypeParameter { /// [TypeParameter]. This will also insert this new list into the current /// namespace. pub(crate) fn type_check_type_params( + handler: &Handler, mut ctx: TypeCheckContext, type_params: Vec, - ) -> CompileResult> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result, ErrorEmitted> { let mut new_type_params: Vec = vec![]; + let mut error_emitted = None; + for type_param in type_params.into_iter() { - new_type_params.push(check!( - TypeParameter::type_check(ctx.by_ref(), type_param), - continue, - warnings, - errors - )); + new_type_params.push( + match TypeParameter::type_check(handler, ctx.by_ref(), type_param) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }, + ) } - if errors.is_empty() { - ok(new_type_params, warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(new_type_params) } } /// Type checks a [TypeParameter] (including its [TraitConstraint]s) and /// inserts into into the current namespace. - fn type_check(mut ctx: TypeCheckContext, type_parameter: TypeParameter) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + fn type_check( + handler: &Handler, + mut ctx: TypeCheckContext, + type_parameter: TypeParameter, + ) -> Result { let type_engine = ctx.engines.te(); let engines = ctx.engines(); @@ -176,12 +182,7 @@ impl TypeParameter { // Type check the trait constraints. for trait_constraint in trait_constraints.iter_mut() { - check!( - trait_constraint.type_check(ctx.by_ref()), - return err(warnings, errors), - warnings, - errors - ); + trait_constraint.type_check(handler, ctx.by_ref())?; } // TODO: add check here to see if the type parameter has a valid name and does not have type parameters @@ -196,12 +197,12 @@ impl TypeParameter { // Insert the trait constraints into the namespace. for trait_constraint in trait_constraints.iter() { - check!( - TraitConstraint::insert_into_namespace(ctx.by_ref(), type_id, trait_constraint), - return err(warnings, errors), - warnings, - errors - ); + TraitConstraint::insert_into_namespace( + handler, + ctx.by_ref(), + type_id, + trait_constraint, + )?; } // When type parameter is from parent then it was already inserted. @@ -213,23 +214,27 @@ impl TypeParameter { type_id: sy_type_id, .. }) => { - append!( - ctx.engines().te().unify( - ctx.engines(), - type_id, - *sy_type_id, - &trait_constraints_span, - "", - None - ), - warnings, - errors + let (warnings, errors) = ctx.engines().te().unify( + ctx.engines(), + type_id, + *sy_type_id, + &trait_constraints_span, + "", + None, ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } + } + _ => { + handler.emit_err(CompileError::Internal( + "Unexpected TyDeclaration for TypeParameter.", + name_ident.span(), + )); } - _ => errors.push(CompileError::Internal( - "Unexpected TyDeclaration for TypeParameter.", - name_ident.span(), - )), } } } else { @@ -240,8 +245,8 @@ impl TypeParameter { name: name_ident.clone(), type_id, }); - ctx.insert_symbol(name_ident.clone(), type_parameter_decl) - .ok(&mut warnings, &mut errors); + ctx.insert_symbol(handler, name_ident.clone(), type_parameter_decl) + .ok(); } let type_parameter = TypeParameter { @@ -252,22 +257,22 @@ impl TypeParameter { trait_constraints_span, is_from_parent, }; - ok(type_parameter, warnings, errors) + Ok(type_parameter) } /// Creates a [DeclMapping] from a list of [TypeParameter]s. pub(crate) fn gather_decl_mapping_from_trait_constraints( + handler: &Handler, mut ctx: TypeCheckContext, type_parameters: &[TypeParameter], access_span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result { let mut interface_item_refs: InterfaceItemMap = BTreeMap::new(); let mut item_refs: ItemMap = BTreeMap::new(); let mut impld_item_refs: ItemMap = BTreeMap::new(); + let mut error_emitted = None; + for type_param in type_parameters.iter() { let TypeParameter { type_id, @@ -276,19 +281,22 @@ impl TypeParameter { } = type_param; // Check to see if the trait constraints are satisfied. - check!( - ctx.namespace - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - *type_id, - trait_constraints, - access_span, - ctx.engines() - ), - continue, - warnings, - errors - ); + match ctx + .namespace + .implemented_traits + .check_if_trait_constraints_are_satisfied_for_type( + handler, + *type_id, + trait_constraints, + access_span, + ctx.engines(), + ) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + } for trait_constraint in trait_constraints.iter() { let TraitConstraint { @@ -296,50 +304,58 @@ impl TypeParameter { type_arguments: trait_type_arguments, } = trait_constraint; - let (trait_interface_item_refs, trait_item_refs, trait_impld_item_refs) = check!( - handle_trait(ctx.by_ref(), *type_id, trait_name, trait_type_arguments), - continue, - warnings, - errors - ); + let (trait_interface_item_refs, trait_item_refs, trait_impld_item_refs) = + match handle_trait( + handler, + ctx.by_ref(), + *type_id, + trait_name, + trait_type_arguments, + ) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }; interface_item_refs.extend(trait_interface_item_refs); item_refs.extend(trait_item_refs); impld_item_refs.extend(trait_impld_item_refs); } } - if errors.is_empty() { + if let Some(err) = error_emitted { + Err(err) + } else { let decl_mapping = DeclMapping::from_interface_and_item_and_impld_decl_refs( interface_item_refs, item_refs, impld_item_refs, ); - ok(decl_mapping, warnings, errors) - } else { - err(warnings, errors) + Ok(decl_mapping) } } } fn handle_trait( + handler: &Handler, mut ctx: TypeCheckContext, type_id: TypeId, trait_name: &CallPath, type_arguments: &[TypeArgument], -) -> CompileResult<(InterfaceItemMap, ItemMap, ItemMap)> { - let mut warnings = vec![]; - let mut errors = vec![]; - +) -> Result<(InterfaceItemMap, ItemMap, ItemMap), ErrorEmitted> { let decl_engine = ctx.engines.de(); let mut interface_item_refs: InterfaceItemMap = BTreeMap::new(); let mut item_refs: ItemMap = BTreeMap::new(); let mut impld_item_refs: ItemMap = BTreeMap::new(); + let mut error_emitted = None; + match ctx .namespace - .resolve_call_path(trait_name) - .ok(&mut warnings, &mut errors) + .resolve_call_path(handler, trait_name) + .ok() .cloned() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { @@ -361,30 +377,29 @@ fn handle_trait( supertrait_interface_item_refs, supertrait_item_refs, supertrait_impld_item_refs, - ) = check!( - handle_trait(ctx.by_ref(), type_id, &supertrait.name, &[]), - continue, - warnings, - errors - ); + ) = match handle_trait(handler, ctx.by_ref(), type_id, &supertrait.name, &[]) { + Ok(res) => res, + Err(err) => { + error_emitted = Some(err); + continue; + } + }; interface_item_refs.extend(supertrait_interface_item_refs); item_refs.extend(supertrait_item_refs); impld_item_refs.extend(supertrait_impld_item_refs); } } - _ => errors.push(CompileError::TraitNotFound { - name: trait_name.to_string(), - span: trait_name.span(), - }), + _ => { + error_emitted = Some(handler.emit_err(CompileError::TraitNotFound { + name: trait_name.to_string(), + span: trait_name.span(), + })); + } } - if errors.is_empty() { - ok( - (interface_item_refs, item_refs, impld_item_refs), - warnings, - errors, - ) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok((interface_item_refs, item_refs, impld_item_refs)) } } diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index e407a55ad04..528ac3fd8f3 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -2,12 +2,12 @@ use core::fmt::Write; use hashbrown::hash_map::RawEntryMut; use hashbrown::HashMap; use std::sync::RwLock; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::integer_bits::IntegerBits; use crate::concurrent_slab::ListDisplay; -use crate::error::{err, ok}; use crate::{ - concurrent_slab::ConcurrentSlab, decl_engine::*, engine_threading::*, error::*, language::ty, + concurrent_slab::ConcurrentSlab, decl_engine::*, engine_threading::*, language::ty, namespace::Path, type_system::priv_prelude::*, Namespace, }; @@ -94,6 +94,7 @@ impl TypeEngine { #[allow(clippy::too_many_arguments)] pub(crate) fn monomorphize( &self, + handler: &Handler, engines: &Engines, value: &mut T, type_arguments: &mut [TypeArgument], @@ -101,29 +102,26 @@ impl TypeEngine { call_site_span: &Span, namespace: &mut Namespace, mod_path: &Path, - ) -> CompileResult<()> + ) -> Result<(), ErrorEmitted> where T: MonomorphizeHelper + SubstTypes, { - let mut warnings = vec![]; - let mut errors = vec![]; match ( value.type_parameters().is_empty(), type_arguments.is_empty(), ) { - (true, true) => ok((), warnings, errors), + (true, true) => Ok(()), (false, true) => { if let EnforceTypeArguments::Yes = enforce_type_arguments { - errors.push(CompileError::NeedsTypeArguments { + return Err(handler.emit_err(CompileError::NeedsTypeArguments { name: value.name().clone(), span: call_site_span.clone(), - }); - return err(warnings, errors); + })); } let type_mapping = TypeSubstMap::from_type_parameters(engines, value.type_parameters()); value.subst(&type_mapping, engines); - ok((), warnings, errors) + Ok(()) } (true, false) => { let type_arguments_span = type_arguments @@ -131,11 +129,10 @@ impl TypeEngine { .map(|x| x.span.clone()) .reduce(Span::join) .unwrap_or_else(|| value.name().span()); - errors.push(CompileError::DoesNotTakeTypeArguments { + Err(handler.emit_err(CompileError::DoesNotTakeTypeArguments { name: value.name().clone(), span: type_arguments_span, - }); - err(warnings, errors) + })) } (false, false) => { let type_arguments_span = type_arguments @@ -144,16 +141,18 @@ impl TypeEngine { .reduce(Span::join) .unwrap_or_else(|| value.name().span()); if value.type_parameters().len() != type_arguments.len() { - errors.push(CompileError::IncorrectNumberOfTypeArguments { - given: type_arguments.len(), - expected: value.type_parameters().len(), - span: type_arguments_span, - }); - return err(warnings, errors); + return Err( + handler.emit_err(CompileError::IncorrectNumberOfTypeArguments { + given: type_arguments.len(), + expected: value.type_parameters().len(), + span: type_arguments_span, + }), + ); } for type_argument in type_arguments.iter_mut() { - type_argument.type_id = check!( - self.resolve( + type_argument.type_id = self + .resolve( + handler, engines, type_argument.type_id, &type_argument.span, @@ -161,11 +160,8 @@ impl TypeEngine { None, namespace, mod_path, - ), - self.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + ) + .unwrap_or_else(|_| self.insert(engines, TypeInfo::ErrorRecovery)); } let type_mapping = TypeSubstMap::from_type_parameters_and_type_arguments( value @@ -179,7 +175,7 @@ impl TypeEngine { .collect(), ); value.subst(&type_mapping, engines); - ok((), warnings, errors) + Ok(()) } } } @@ -309,64 +305,34 @@ impl TypeEngine { /// Resolve all inner types that still are a [TypeInfo::Numeric] to a concrete `u64` pub(crate) fn decay_numeric( &self, + handler: &Handler, engines: &Engines, type_id: TypeId, span: &Span, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; - + ) -> Result<(), ErrorEmitted> { let decl_engine = engines.de(); match &self.get(type_id) { TypeInfo::Enum(decl_ref) => { for variant_type in decl_engine.get_enum(decl_ref).variants.iter() { - check!( - self.decay_numeric(engines, variant_type.type_argument.type_id, span), - return err(warnings, errors), - warnings, - errors - ) + self.decay_numeric(handler, engines, variant_type.type_argument.type_id, span)?; } } TypeInfo::Struct(decl_ref) => { for field in decl_engine.get_struct(decl_ref).fields.iter() { - check!( - self.decay_numeric(engines, field.type_argument.type_id, span), - return err(warnings, errors), - warnings, - errors - ) + self.decay_numeric(handler, engines, field.type_argument.type_id, span)?; } } TypeInfo::Tuple(fields) => { for field_type in fields { - check!( - self.decay_numeric(engines, field_type.type_id, span), - return err(warnings, errors), - warnings, - errors - ) + self.decay_numeric(handler, engines, field_type.type_id, span)?; } } - TypeInfo::Array(elem_ty, _length) => check!( - self.decay_numeric(engines, elem_ty.type_id, span), - return err(warnings, errors), - warnings, - errors - ), - TypeInfo::Ptr(targ) => check!( - self.decay_numeric(engines, targ.type_id, span), - return err(warnings, errors), - warnings, - errors - ), - TypeInfo::Slice(targ) => check!( - self.decay_numeric(engines, targ.type_id, span), - return err(warnings, errors), - warnings, - errors - ), + TypeInfo::Array(elem_ty, _length) => { + self.decay_numeric(handler, engines, elem_ty.type_id, span)? + } + TypeInfo::Ptr(targ) => self.decay_numeric(handler, engines, targ.type_id, span)?, + TypeInfo::Slice(targ) => self.decay_numeric(handler, engines, targ.type_id, span)?, TypeInfo::Unknown | TypeInfo::UnknownGeneric { .. } @@ -386,22 +352,23 @@ impl TypeEngine { | TypeInfo::RawUntypedSlice | TypeInfo::Alias { .. } => {} TypeInfo::Numeric => { - check!( - CompileResult::from(self.unify( - engines, - type_id, - self.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), - span, - "", - None, - )), - (), - warnings, - errors, + let (warnings, errors) = self.unify( + engines, + type_id, + self.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + span, + "", + None, ); + for warn in warnings { + handler.emit_warn(warn); + } + for err in errors { + handler.emit_err(err); + } } } - ok((), warnings, errors) + Ok(()) } /// Resolve the type of the given [TypeId], replacing any instances of @@ -410,6 +377,7 @@ impl TypeEngine { #[allow(clippy::too_many_arguments)] pub(crate) fn resolve( &self, + handler: &Handler, engines: &Engines, type_id: TypeId, span: &Span, @@ -417,9 +385,7 @@ impl TypeEngine { type_info_prefix: Option<&Path>, namespace: &mut Namespace, mod_path: &Path, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result { let decl_engine = engines.de(); let module_path = type_info_prefix.unwrap_or(mod_path); let type_id = match self.get(type_id) { @@ -429,8 +395,13 @@ impl TypeEngine { } => { match namespace .root() - .resolve_call_path_with_visibility_check(engines, module_path, &call_path) - .ok(&mut warnings, &mut errors) + .resolve_call_path_with_visibility_check( + handler, + engines, + module_path, + &call_path, + ) + .ok() .cloned() { Some(ty::TyDecl::StructDecl(ty::StructDecl { @@ -441,20 +412,16 @@ impl TypeEngine { let mut new_copy = decl_engine.get_struct(&original_id); // monomorphize the copy, in place - check!( - self.monomorphize( - engines, - &mut new_copy, - &mut type_arguments.unwrap_or_default(), - enforce_type_arguments, - span, - namespace, - mod_path, - ), - return err(warnings, errors), - warnings, - errors, - ); + self.monomorphize( + handler, + engines, + &mut new_copy, + &mut type_arguments.unwrap_or_default(), + enforce_type_arguments, + span, + namespace, + mod_path, + )?; // insert the new copy in the decl engine let new_decl_ref = decl_engine.insert(new_copy); @@ -476,20 +443,16 @@ impl TypeEngine { let mut new_copy = decl_engine.get_enum(&original_id); // monomorphize the copy, in place - check!( - self.monomorphize( - engines, - &mut new_copy, - &mut type_arguments.unwrap_or_default(), - enforce_type_arguments, - span, - namespace, - mod_path, - ), - return err(warnings, errors), - warnings, - errors - ); + self.monomorphize( + handler, + engines, + &mut new_copy, + &mut type_arguments.unwrap_or_default(), + enforce_type_arguments, + span, + namespace, + mod_path, + )?; // insert the new copy in the decl engine let new_decl_ref = decl_engine.insert(new_copy); @@ -521,7 +484,7 @@ impl TypeEngine { ty::GenericTypeForFunctionScope { type_id, .. }, )) => type_id, _ => { - errors.push(CompileError::UnknownTypeName { + handler.emit_err(CompileError::UnknownTypeName { name: call_path.to_string(), span: call_path.span(), }); @@ -530,8 +493,9 @@ impl TypeEngine { } } TypeInfo::Array(mut elem_ty, n) => { - elem_ty.type_id = check!( - self.resolve( + elem_ty.type_id = self + .resolve( + handler, engines, elem_ty.type_id, span, @@ -539,11 +503,8 @@ impl TypeEngine { None, namespace, mod_path, - ), - self.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + ) + .unwrap_or_else(|_| self.insert(engines, TypeInfo::ErrorRecovery)); let type_id = self.insert(engines, TypeInfo::Array(elem_ty, n)); @@ -554,8 +515,9 @@ impl TypeEngine { } TypeInfo::Tuple(mut type_arguments) => { for type_argument in type_arguments.iter_mut() { - type_argument.type_id = check!( - self.resolve( + type_argument.type_id = self + .resolve( + handler, engines, type_argument.type_id, span, @@ -563,11 +525,8 @@ impl TypeEngine { None, namespace, mod_path, - ), - self.insert(engines, TypeInfo::ErrorRecovery), - warnings, - errors - ); + ) + .unwrap_or_else(|_| self.insert(engines, TypeInfo::ErrorRecovery)); } let type_id = self.insert(engines, TypeInfo::Tuple(type_arguments)); @@ -579,7 +538,7 @@ impl TypeEngine { } _ => type_id, }; - ok(type_id, warnings, errors) + Ok(type_id) } /// Replace any instances of the [TypeInfo::SelfType] variant with @@ -587,6 +546,7 @@ impl TypeEngine { #[allow(clippy::too_many_arguments)] pub(crate) fn resolve_with_self( &self, + handler: &Handler, engines: &Engines, mut type_id: TypeId, self_type: TypeId, @@ -595,9 +555,10 @@ impl TypeEngine { type_info_prefix: Option<&Path>, namespace: &mut Namespace, mod_path: &Path, - ) -> CompileResult { + ) -> Result { type_id.replace_self_type(engines, self_type); self.resolve( + handler, engines, type_id, span, diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index f1d2ab5278d..623961d2bf3 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -1,10 +1,12 @@ -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{BaseIdent, Span}; use crate::{ decl_engine::{DeclEngine, DeclEngineInsert}, engine_threading::*, - error::*, language::CallPath, semantic_analysis::TypeCheckContext, type_system::priv_prelude::*, @@ -41,8 +43,9 @@ impl From for TypeId { impl CollectTypesMetadata for TypeId { fn collect_types_metadata( &self, + _handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult> { + ) -> Result, ErrorEmitted> { fn filter_fn(type_info: &TypeInfo) -> bool { matches!(type_info, TypeInfo::UnknownGeneric { .. }) || matches!(type_info, TypeInfo::Placeholder(_)) @@ -67,7 +70,7 @@ impl CollectTypesMetadata for TypeId { _ => {} } } - ok(res, vec![], vec![]) + Ok(res) } } @@ -361,12 +364,11 @@ impl TypeId { /// is thrown. pub(crate) fn check_type_parameter_bounds( &self, + handler: &Handler, ctx: &TypeCheckContext, span: &Span, trait_constraints: Vec, - ) -> CompileResult<()> { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result<(), ErrorEmitted> { let engines = ctx.engines(); let mut structure_generics = engines @@ -378,20 +380,17 @@ impl TypeId { structure_generics.insert(*self, trait_constraints); } + let mut error_emitted = None; + for (structure_type_id, structure_trait_constraints) in &structure_generics { if structure_trait_constraints.is_empty() { continue; } // resolving trait constraits require a concrete type, we need to default numeric to u64 - check!( - engines - .te() - .decay_numeric(engines, *structure_type_id, span), - return err(warnings, errors), - warnings, - errors - ); + engines + .te() + .decay_numeric(handler, engines, *structure_type_id, span)?; let structure_type_info = engines.te().get(*structure_type_id); let structure_type_info_with_engines = engines.help_out(structure_type_info.clone()); @@ -407,11 +406,13 @@ impl TypeId { if !generic_trait_constraints_trait_names .contains(&structure_trait_constraint.trait_name) { - errors.push(CompileError::TraitConstraintMissing { - param: structure_type_info_with_engines.to_string(), - trait_name: structure_trait_constraint.trait_name.suffix.to_string(), - span: span.clone(), - }); + error_emitted = + Some(handler.emit_err(CompileError::TraitConstraintMissing { + param: structure_type_info_with_engines.to_string(), + trait_name: + structure_trait_constraint.trait_name.suffix.to_string(), + span: span.clone(), + })); } } } else { @@ -425,20 +426,22 @@ impl TypeId { .trait_name .to_fullpath(ctx.namespace), ) { - errors.push(CompileError::TraitConstraintNotSatisfied { - ty: structure_type_info_with_engines.to_string(), - trait_name: structure_trait_constraint.trait_name.suffix.to_string(), - span: span.clone(), - }); + error_emitted = + Some(handler.emit_err(CompileError::TraitConstraintNotSatisfied { + ty: structure_type_info_with_engines.to_string(), + trait_name: + structure_trait_constraint.trait_name.suffix.to_string(), + span: span.clone(), + })); } } } } - if errors.is_empty() { - ok((), warnings, errors) + if let Some(err) = error_emitted { + Err(err) } else { - err(warnings, errors) + Ok(()) } } } diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 2d73371ff11..bc01cf005d4 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -1,12 +1,14 @@ use crate::{ decl_engine::{DeclEngine, DeclRefEnum, DeclRefStruct}, engine_threading::*, - error::*, language::{ty, CallPath}, type_system::priv_prelude::*, Ident, }; -use sway_error::error::CompileError; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; use sway_types::{integer_bits::IntegerBits, span::Span, Spanned}; use std::{ @@ -599,9 +601,10 @@ impl TypeInfo { /// maps a type to a name that is used when constructing function selectors pub(crate) fn to_selector_name( &self, + handler: &Handler, engines: &Engines, error_msg_span: &Span, - ) -> CompileResult { + ) -> Result { let type_engine = engines.te(); let decl_engine = engines.de(); use TypeInfo::*; @@ -627,15 +630,12 @@ impl TypeInfo { type_engine .to_typeinfo(field_type.type_id, error_msg_span) .expect("unreachable?") - .to_selector_name(engines, error_msg_span) + .to_selector_name(handler, engines, error_msg_span) }) - .collect::>>(); + .collect::>>(); let mut buf = vec![]; for name in names { - match name.value { - Some(value) => buf.push(value), - None => return name, - } + buf.push(name?); } buf }; @@ -653,17 +653,17 @@ impl TypeInfo { let ty = match type_engine .to_typeinfo(ty.type_argument.type_id, error_msg_span) { - Err(e) => return err(vec![], vec![e.into()]), + Err(e) => return Err(handler.emit_err(e.into())), Ok(ty) => ty, }; - ty.to_selector_name(engines, error_msg_span) + ty.to_selector_name(handler, engines, error_msg_span) }) - .collect::>>(); + .collect::>>(); let mut buf = vec![]; for name in names { - match name.value { - Some(value) => buf.push(value), - None => return name, + match name { + Ok(value) => buf.push(value), + Err(e) => return Err(e), } } buf @@ -675,17 +675,17 @@ impl TypeInfo { .iter() .map(|ty| { let ty = match type_engine.to_typeinfo(ty.type_id, error_msg_span) { - Err(e) => return err(vec![], vec![e.into()]), + Err(e) => return Err(handler.emit_err(e.into())), Ok(ty) => ty, }; - ty.to_selector_name(engines, error_msg_span) + ty.to_selector_name(handler, engines, error_msg_span) }) - .collect::>>(); + .collect::>>(); let mut buf = vec![]; for arg in type_arguments { - match arg.value { - Some(value) => buf.push(value), - None => return arg, + match arg { + Ok(value) => buf.push(value), + Err(e) => return Err(e), } } buf @@ -707,18 +707,15 @@ impl TypeInfo { let ty = match type_engine .to_typeinfo(ty.type_argument.type_id, error_msg_span) { - Err(e) => return err(vec![], vec![e.into()]), + Err(e) => return Err(handler.emit_err(e.into())), Ok(ty) => ty, }; - ty.to_selector_name(engines, error_msg_span) + ty.to_selector_name(handler, engines, error_msg_span) }) - .collect::>>(); + .collect::>>(); let mut buf = vec![]; for name in names { - match name.value { - Some(value) => buf.push(value), - None => return name, - } + buf.push(name?); } buf }; @@ -729,18 +726,15 @@ impl TypeInfo { .iter() .map(|ty| { let ty = match type_engine.to_typeinfo(ty.type_id, error_msg_span) { - Err(e) => return err(vec![], vec![e.into()]), + Err(e) => return Err(handler.emit_err(e.into())), Ok(ty) => ty, }; - ty.to_selector_name(engines, error_msg_span) + ty.to_selector_name(handler, engines, error_msg_span) }) - .collect::>>(); + .collect::>>(); let mut buf = vec![]; for arg in type_arguments { - match arg.value { - Some(value) => buf.push(value), - None => return arg, - } + buf.push(arg?); } buf }; @@ -755,36 +749,33 @@ impl TypeInfo { } } Array(elem_ty, length) => { - let name = type_engine - .get(elem_ty.type_id) - .to_selector_name(engines, error_msg_span); - let name = match name.value { - Some(name) => name, - None => return name, + let name = type_engine.get(elem_ty.type_id).to_selector_name( + handler, + engines, + error_msg_span, + ); + let name = match name { + Ok(name) => name, + Err(e) => return Err(e), }; format!("a[{};{}]", name, length.val()) } RawUntypedPtr => "rawptr".to_string(), RawUntypedSlice => "rawslice".to_string(), Alias { ty, .. } => { - let name = type_engine - .get(ty.type_id) - .to_selector_name(engines, error_msg_span); - match name.value { - Some(name) => name, - None => return name, - } + let name = + type_engine + .get(ty.type_id) + .to_selector_name(handler, engines, error_msg_span); + name? } _ => { - return err( - vec![], - vec![CompileError::InvalidAbiType { - span: error_msg_span.clone(), - }], - ) + return Err(handler.emit_err(CompileError::InvalidAbiType { + span: error_msg_span.clone(), + })); } }; - ok(name, vec![], vec![]) + Ok(name) } pub fn is_uninhabited(&self, type_engine: &TypeEngine, decl_engine: &DeclEngine) -> bool { @@ -915,35 +906,33 @@ impl TypeInfo { pub(crate) fn apply_type_arguments( self, + handler: &Handler, type_arguments: Vec, span: &Span, - ) -> CompileResult { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result { if type_arguments.is_empty() { - return ok(self, warnings, errors); + return Ok(self); } match self { TypeInfo::Enum { .. } | TypeInfo::Struct { .. } => { - errors.push(CompileError::Internal( + Err(handler.emit_err(CompileError::Internal( "did not expect to apply type arguments to this type", span.clone(), - )); - err(warnings, errors) + ))) } TypeInfo::Custom { call_path, type_arguments: other_type_arguments, } => { if other_type_arguments.is_some() { - errors.push(CompileError::TypeArgumentsNotAllowed { span: span.clone() }); - err(warnings, errors) + Err(handler + .emit_err(CompileError::TypeArgumentsNotAllowed { span: span.clone() })) } else { let type_info = TypeInfo::Custom { call_path, type_arguments: Some(type_arguments), }; - ok(type_info, warnings, errors) + Ok(type_info) } } TypeInfo::Unknown @@ -967,8 +956,7 @@ impl TypeInfo { | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) | TypeInfo::Alias { .. } => { - errors.push(CompileError::TypeArgumentsNotAllowed { span: span.clone() }); - err(warnings, errors) + Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span: span.clone() })) } } } @@ -999,10 +987,9 @@ impl TypeInfo { /// supported in match expressions, and return an error if it is not. pub(crate) fn expect_is_supported_in_match_expressions( &self, + handler: &Handler, span: &Span, - ) -> CompileResult<()> { - let warnings = vec![]; - let mut errors = vec![]; + ) -> Result<(), ErrorEmitted> { match self { TypeInfo::UnsignedInteger(_) | TypeInfo::Enum { .. } @@ -1012,7 +999,7 @@ impl TypeInfo { | TypeInfo::B256 | TypeInfo::UnknownGeneric { .. } | TypeInfo::Numeric - | TypeInfo::Alias { .. } => ok((), warnings, errors), + | TypeInfo::Alias { .. } => Ok(()), TypeInfo::Unknown | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice @@ -1026,25 +1013,24 @@ impl TypeInfo { | TypeInfo::Array(_, _) | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) - | TypeInfo::TypeParam(_) => { - errors.push(CompileError::Unimplemented( - "matching on this type is unsupported right now", - span.clone(), - )); - err(warnings, errors) - } + | TypeInfo::TypeParam(_) => Err(handler.emit_err(CompileError::Unimplemented( + "matching on this type is unsupported right now", + span.clone(), + ))), TypeInfo::ErrorRecovery => { // return an error but don't create a new error message - err(warnings, errors) + Err(ErrorEmitted) } } } /// Given a `TypeInfo` `self`, check to see if `self` is currently /// supported in `impl` blocks in the "type implementing for" position. - pub(crate) fn expect_is_supported_in_impl_blocks_self(&self, span: &Span) -> CompileResult<()> { - let warnings = vec![]; - let mut errors = vec![]; + pub(crate) fn expect_is_supported_in_impl_blocks_self( + &self, + handler: &Handler, + span: &Span, + ) -> Result<(), ErrorEmitted> { match self { TypeInfo::UnsignedInteger(_) | TypeInfo::Enum { .. } @@ -1062,22 +1048,19 @@ impl TypeInfo { | TypeInfo::Contract | TypeInfo::Numeric | TypeInfo::Alias { .. } - | TypeInfo::UnknownGeneric { .. } => ok((), warnings, errors), + | TypeInfo::UnknownGeneric { .. } => Ok(()), TypeInfo::Unknown | TypeInfo::ContractCaller { .. } | TypeInfo::SelfType | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) - | TypeInfo::TypeParam(_) => { - errors.push(CompileError::Unimplemented( - "implementing traits on this type is unsupported right now", - span.clone(), - )); - err(warnings, errors) - } + | TypeInfo::TypeParam(_) => Err(handler.emit_err(CompileError::Unimplemented( + "implementing traits on this type is unsupported right now", + span.clone(), + ))), TypeInfo::ErrorRecovery => { // return an error but don't create a new error message - err(warnings, errors) + Err(ErrorEmitted) } } } @@ -1302,16 +1285,15 @@ impl TypeInfo { /// 3) in the case where a `subfield` does not exist on `self` pub(crate) fn apply_subfields( &self, + handler: &Handler, engines: &Engines, subfields: &[Ident], span: &Span, - ) -> CompileResult { - let mut warnings = vec![]; - let mut errors = vec![]; + ) -> Result { let type_engine = engines.te(); let decl_engine = engines.de(); match (self, subfields.split_first()) { - (TypeInfo::Struct { .. } | TypeInfo::Alias { .. }, None) => err(warnings, errors), + (TypeInfo::Struct { .. } | TypeInfo::Alias { .. }, None) => Err(ErrorEmitted), (TypeInfo::Struct(decl_ref), Some((first, rest))) => { let decl = decl_engine.get_struct(decl_ref); let field = match decl @@ -1327,28 +1309,22 @@ impl TypeInfo { .iter() .map(|x| x.name.as_str()) .collect::>(); - errors.push(CompileError::FieldNotFound { + return Err(handler.emit_err(CompileError::FieldNotFound { field_name: first.clone(), struct_name: decl.call_path.suffix.clone(), available_fields: available_fields.join(", "), span: first.span(), - }); - return err(warnings, errors); + })); } }; let field = if rest.is_empty() { field } else { - check!( - type_engine - .get(field.type_argument.type_id) - .apply_subfields(engines, rest, span), - return err(warnings, errors), - warnings, - errors - ) + type_engine + .get(field.type_argument.type_id) + .apply_subfields(handler, engines, rest, span)? }; - ok(field, warnings, errors) + Ok(field) } ( TypeInfo::Alias { @@ -1358,18 +1334,15 @@ impl TypeInfo { _, ) => type_engine .get(*type_id) - .apply_subfields(engines, subfields, span), + .apply_subfields(handler, engines, subfields, span), (TypeInfo::ErrorRecovery, _) => { // dont create a new error in this case - err(warnings, errors) - } - (type_info, _) => { - errors.push(CompileError::FieldAccessOnNonStruct { - actually: format!("{:?}", engines.help_out(type_info)), - span: span.clone(), - }); - err(warnings, errors) + Err(ErrorEmitted) } + (type_info, _) => Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { + actually: format!("{:?}", engines.help_out(type_info)), + span: span.clone(), + })), } } @@ -1441,30 +1414,28 @@ impl TypeInfo { /// type, transitively. pub(crate) fn expect_tuple( &self, + handler: &Handler, engines: &Engines, debug_string: impl Into, debug_span: &Span, - ) -> CompileResult> { - let warnings = vec![]; - let errors = vec![]; + ) -> Result, ErrorEmitted> { match self { - TypeInfo::Tuple(elems) => ok(elems.to_vec(), warnings, errors), + TypeInfo::Tuple(elems) => Ok(elems.to_vec()), TypeInfo::Alias { ty: TypeArgument { type_id, .. }, .. - } => engines - .te() - .get(*type_id) - .expect_tuple(engines, debug_string, debug_span), - TypeInfo::ErrorRecovery => err(warnings, errors), - a => err( - vec![], - vec![CompileError::NotATuple { - name: debug_string.into(), - span: debug_span.clone(), - actually: engines.help_out(a).to_string(), - }], - ), + } => { + engines + .te() + .get(*type_id) + .expect_tuple(handler, engines, debug_string, debug_span) + } + TypeInfo::ErrorRecovery => Err(ErrorEmitted), + a => Err(handler.emit_err(CompileError::NotATuple { + name: debug_string.into(), + span: debug_span.clone(), + actually: engines.help_out(a).to_string(), + })), } } @@ -1486,30 +1457,26 @@ impl TypeInfo { /// transitively. pub(crate) fn expect_enum( &self, + handler: &Handler, engines: &Engines, debug_string: impl Into, debug_span: &Span, - ) -> CompileResult { - let warnings = vec![]; - let errors = vec![]; + ) -> Result { match self { - TypeInfo::Enum(decl_ref) => ok(decl_ref.clone(), warnings, errors), + TypeInfo::Enum(decl_ref) => Ok(decl_ref.clone()), TypeInfo::Alias { ty: TypeArgument { type_id, .. }, .. } => engines .te() .get(*type_id) - .expect_enum(engines, debug_string, debug_span), - TypeInfo::ErrorRecovery => err(warnings, errors), - a => err( - vec![], - vec![CompileError::NotAnEnum { - name: debug_string.into(), - span: debug_span.clone(), - actually: engines.help_out(a).to_string(), - }], - ), + .expect_enum(handler, engines, debug_string, debug_span), + TypeInfo::ErrorRecovery => Err(ErrorEmitted), + a => Err(handler.emit_err(CompileError::NotAnEnum { + name: debug_string.into(), + span: debug_span.clone(), + actually: engines.help_out(a).to_string(), + })), } } @@ -1532,28 +1499,24 @@ impl TypeInfo { #[allow(dead_code)] pub(crate) fn expect_struct( &self, + handler: &Handler, engines: &Engines, debug_span: &Span, - ) -> CompileResult { - let warnings = vec![]; - let errors = vec![]; + ) -> Result { match self { - TypeInfo::Struct(decl_ref) => ok(decl_ref.clone(), warnings, errors), + TypeInfo::Struct(decl_ref) => Ok(decl_ref.clone()), TypeInfo::Alias { ty: TypeArgument { type_id, .. }, .. } => engines .te() .get(*type_id) - .expect_struct(engines, debug_span), - TypeInfo::ErrorRecovery => err(warnings, errors), - a => err( - vec![], - vec![CompileError::NotAStruct { - span: debug_span.clone(), - actually: engines.help_out(a).to_string(), - }], - ), + .expect_struct(handler, engines, debug_span), + TypeInfo::ErrorRecovery => Err(ErrorEmitted), + a => Err(handler.emit_err(CompileError::NotAStruct { + span: debug_span.clone(), + actually: engines.help_out(a).to_string(), + })), } } } diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index d0cc60ddec8..f75aa1ecdbd 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -291,11 +291,9 @@ impl<'a> Unifier<'a> { let mut warnings = vec![]; let mut errors = vec![]; for (rf, ef) in rfs.iter().zip(efs.iter()) { - append!( - self.unify(rf.type_id, ef.type_id, &rf.span), - warnings, - errors - ); + let (mut warns, mut errs) = self.unify(rf.type_id, ef.type_id, &rf.span); + warnings.append(&mut warns); + errors.append(&mut errs); } (warnings, errors) } @@ -314,14 +312,15 @@ impl<'a> Unifier<'a> { let (en, etps, efs) = e; if rn == en && rfs.len() == efs.len() && rtps.len() == etps.len() { rfs.iter().zip(efs.iter()).for_each(|(rf, ef)| { - append!( - self.unify(rf.type_argument.type_id, ef.type_argument.type_id, span), - warnings, - errors - ); + let (mut warns, mut errs) = + self.unify(rf.type_argument.type_id, ef.type_argument.type_id, span); + warnings.append(&mut warns); + errors.append(&mut errs); }); rtps.iter().zip(etps.iter()).for_each(|(rtp, etp)| { - append!(self.unify(rtp.type_id, etp.type_id, span), warnings, errors); + let (mut warns, mut errs) = self.unify(rtp.type_id, etp.type_id, span); + warnings.append(&mut warns); + errors.append(&mut errs); }); } else { let (received, expected) = self.assign_args(received, expected); @@ -349,14 +348,15 @@ impl<'a> Unifier<'a> { let (en, etps, evs) = e; if rn == en && rvs.len() == evs.len() && rtps.len() == etps.len() { rvs.iter().zip(evs.iter()).for_each(|(rv, ev)| { - append!( - self.unify(rv.type_argument.type_id, ev.type_argument.type_id, span), - warnings, - errors - ); + let (mut warns, mut errs) = + self.unify(rv.type_argument.type_id, ev.type_argument.type_id, span); + warnings.append(&mut warns); + errors.append(&mut errs); }); rtps.iter().zip(etps.iter()).for_each(|(rtp, etp)| { - append!(self.unify(rtp.type_id, etp.type_id, span), warnings, errors); + let (mut warns, mut errs) = self.unify(rtp.type_id, etp.type_id, span); + warnings.append(&mut warns); + errors.append(&mut errs); }); } else { let (received, expected) = self.assign_args(received, expected); diff --git a/sway-core/src/types/collect_types_metadata.rs b/sway-core/src/types/collect_types_metadata.rs index c81349303b8..a219ecc20a7 100644 --- a/sway-core/src/types/collect_types_metadata.rs +++ b/sway-core/src/types/collect_types_metadata.rs @@ -8,7 +8,8 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::{type_system::TypeId, CompileResult, Engines}; +use crate::{type_system::TypeId, Engines}; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{Ident, Span}; /// If any types contained by this node are unresolved or have yet to be inferred, throw an @@ -131,6 +132,7 @@ impl<'cx> CollectTypesMetadataContext<'cx> { pub(crate) trait CollectTypesMetadata { fn collect_types_metadata( &self, + handler: &Handler, ctx: &mut CollectTypesMetadataContext, - ) -> CompileResult>; + ) -> Result, ErrorEmitted>; } diff --git a/sway-error/Cargo.toml b/sway-error/Cargo.toml index 138aa11b1fb..e877c8fe7b9 100644 --- a/sway-error/Cargo.toml +++ b/sway-error/Cargo.toml @@ -12,6 +12,7 @@ repository.workspace = true extension-trait = "1.0.1" num-bigint = "0.4.3" num-traits = "0.2.14" +smallvec = "1.7" sway-ast = { version = "0.42.1", path = "../sway-ast" } sway-types = { version = "0.42.1", path = "../sway-types" } thiserror = "1.0" diff --git a/sway-error/src/handler.rs b/sway-error/src/handler.rs index fd5c56f5f9e..25c7cb940bd 100644 --- a/sway-error/src/handler.rs +++ b/sway-error/src/handler.rs @@ -1,9 +1,10 @@ use crate::{error::CompileError, warning::CompileWarning}; +use std::collections::HashMap; use core::cell::RefCell; /// A handler with which you can emit diagnostics. -#[derive(Default)] +#[derive(Default, Debug)] pub struct Handler { /// The inner handler. /// This construction is used to avoid `&mut` all over the compiler. @@ -12,7 +13,7 @@ pub struct Handler { /// Contains the actual data for `Handler`. /// Modelled this way to afford an API using interior mutability. -#[derive(Default)] +#[derive(Default, Debug)] struct HandlerInner { /// The sink through which errors will be emitted. errors: Vec, @@ -21,10 +22,16 @@ struct HandlerInner { } impl Handler { + pub fn from_parts(errors: Vec, warnings: Vec) -> Self { + Self { + inner: RefCell::new(HandlerInner { errors, warnings }), + } + } + /// Emit the error `err`. pub fn emit_err(&self, err: CompileError) -> ErrorEmitted { self.inner.borrow_mut().errors.push(err); - ErrorEmitted { _priv: () } + ErrorEmitted } /// Emit the warning `warn`. @@ -32,15 +39,77 @@ impl Handler { self.inner.borrow_mut().warnings.push(warn); } + pub fn has_error(&self) -> bool { + !self.inner.borrow().errors.is_empty() + } + + pub fn has_warning(&self) -> bool { + !self.inner.borrow().warnings.is_empty() + } + /// Extract all the errors from this handler. pub fn consume(self) -> (Vec, Vec) { let inner = self.inner.into_inner(); (inner.errors, inner.warnings) } + + pub fn append(&self, other: Handler) { + let (errors, warnings) = other.consume(); + for warn in warnings { + self.emit_warn(warn); + } + for err in errors { + self.emit_err(err); + } + } + + pub fn dedup(&self) { + let mut inner = self.inner.borrow_mut(); + inner.errors = dedup_unsorted(inner.errors.clone()); + inner.warnings = dedup_unsorted(inner.warnings.clone()); + } } /// Proof that an error was emitted through a `Handler`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ErrorEmitted { - _priv: (), +pub struct ErrorEmitted; + +/// We want compile errors and warnings to retain their ordering, since typically +/// they are grouped by relevance. However, we want to deduplicate them. +/// Stdlib dedup in Rust assumes sorted data for efficiency, but we don't want that. +/// A hash set would also mess up the order, so this is just a brute force way of doing it +/// with a vector. +fn dedup_unsorted(mut data: Vec) -> Vec { + // TODO(Centril): Consider using `IndexSet` instead for readability. + use smallvec::SmallVec; + use std::collections::hash_map::{DefaultHasher, Entry}; + use std::hash::Hasher; + + let mut write_index = 0; + let mut indexes: HashMap> = HashMap::with_capacity(data.len()); + for read_index in 0..data.len() { + let hash = { + let mut hasher = DefaultHasher::new(); + data[read_index].hash(&mut hasher); + hasher.finish() + }; + let index_vec = match indexes.entry(hash) { + Entry::Occupied(oe) => { + if oe + .get() + .iter() + .any(|index| data[*index] == data[read_index]) + { + continue; + } + oe.into_mut() + } + Entry::Vacant(ve) => ve.insert(SmallVec::new()), + }; + data.swap(write_index, read_index); + index_vec.push(write_index); + write_index += 1; + } + data.truncate(write_index); + data } diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index 86ffe889cef..fd6474bbbff 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -38,7 +38,7 @@ use sway_core::{ parsed::{AstNode, ParseProgram}, ty, }, - BuildTarget, CompileResult, Engines, Namespace, Programs, + BuildTarget, Engines, Namespace, Programs, }; use sway_types::{Span, Spanned}; use sway_utils::helpers::get_sway_files; @@ -200,13 +200,9 @@ impl Session { self.runnables.clear(); let results_len = results.len(); - for (i, res) in results.into_iter().enumerate() { + for (i, (value, handler)) in results.into_iter().enumerate() { // We can convert these destructured elements to a Vec later on. - let CompileResult { - value, - warnings, - errors, - } = res; + let (errors, warnings) = handler.consume(); if value.is_none() { // If there was an unrecoverable error in the parser @@ -220,11 +216,9 @@ impl Session { typed, } = value.unwrap(); - let ast_res = CompileResult::new(typed, warnings, errors); - // Get a reference to the typed program AST. - let typed_program = ast_res.value.as_ref().ok_or_else(|| { - *diagnostics = get_diagnostics(&ast_res.warnings, &ast_res.errors); + let typed_program = typed.as_ref().ok_or_else(|| { + *diagnostics = get_diagnostics(&warnings, &errors); LanguageServerError::FailedToParse })?; @@ -255,7 +249,7 @@ impl Session { self.save_parsed_program(parsed.to_owned().clone()); self.save_typed_program(typed_program.to_owned().clone()); - *diagnostics = get_diagnostics(&ast_res.warnings, &ast_res.errors); + *diagnostics = get_diagnostics(&warnings, &errors); } else { // Collect tokens from dependencies and the standard library prelude. self.parse_ast_to_tokens(&parsed, &ctx, |an, ctx| { diff --git a/test/Cargo.toml b/test/Cargo.toml index 1feb637d9ea..58159a03dfd 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -28,6 +28,7 @@ regex = "1.7" revm = "2.3.1" serde_json = "1.0.73" sway-core = { path = "../sway-core" } +sway-error = { path = "../sway-error" } sway-ir = { path = "../sway-ir" } sway-types = { path = "../sway-types" } sway-utils = { path = "../sway-utils" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/method_requires_mut_var/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/method_requires_mut_var/test.toml index 00921d33123..10ed4df3eda 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/method_requires_mut_var/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/method_requires_mut_var/test.toml @@ -1,5 +1,6 @@ category = "fail" +# check: $()self.a.f(); # check: $()self.a.f(); # nextln: $()Cannot call method "f" on variable "self" because "self" is not declared as mutable. diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/type_alias_private/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/type_alias_private/test.toml index 830c8bf5341..88ac3812da1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/type_alias_private/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/type_alias_private/test.toml @@ -1,4 +1,8 @@ category = "fail" +# check: $()fn foo(x: lib::Alias) {} + +# check: $()fn foo(x: lib::Alias) {} + # check: $()fn foo(x: lib::Alias) {} # nextln: $()Symbol "Alias" is private. diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/test.toml index 3124fd485d6..20ba9ab1c2c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/where_clause_impls/test.toml @@ -1,11 +1,10 @@ category = "fail" +# check: $()x: a.x.my_add(b.x), + # check: $()x: a.x.my_add(b.x), # nextln: $()No method named "my_add" found for type "T". # check: $()y: a.y.my_add(b.y), # check: $()y: a.y.my_add(b.y), # nextln: $()No method named "my_add" found for type "T". - -# check: $()let baz = foo.my_add(bar); -# nextln: $()No method named "my_add" found for type "MyPoint". diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index dabd3835c70..49674ebf3db 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -11,6 +11,8 @@ use sway_core::{ compile_ir_to_asm, compile_to_ast, ir_generation::compile_program, namespace, BuildTarget, Engines, }; +use sway_error::handler::Handler; + use sway_ir::{ create_inline_in_module_pass, register_known_passes, PassGroup, PassManager, ARGDEMOTION_NAME, CONSTDEMOTION_NAME, DCE_NAME, MEMCPYOPT_NAME, MISCDEMOTION_NAME, RETDEMOTION_NAME, @@ -219,7 +221,8 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>, verbose: bool) -> R let mut metrics = PerformanceData::default(); let sway_str = String::from_utf8_lossy(&sway_str); - let compile_res = compile_to_ast( + let handler = Handler::default(); let compile_res = compile_to_ast( + &handler, &engines, Arc::from(sway_str), core_lib.clone(), @@ -227,12 +230,12 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>, verbose: bool) -> R "test_lib", &mut metrics, ); - if !compile_res.errors.is_empty() { + let (errors, _warnings) = handler.consume(); + if !errors.is_empty() { panic!( "Failed to compile test {}:\n{}", path.display(), - compile_res - .errors + errors .iter() .map(|err| err.to_string()) .collect::>() @@ -241,7 +244,6 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>, verbose: bool) -> R ); } let programs = compile_res - .value .expect("there were no errors, so there should be a program"); let typed_program = programs.typed.as_ref().unwrap(); @@ -282,8 +284,7 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>, verbose: bool) -> R panic!( "Failed to compile test {}:\n{}", path.display(), - compile_res - .errors + errors .iter() .map(|err| err.to_string()) .collect::>() @@ -378,8 +379,7 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>, verbose: bool) -> R panic!( "Failed to compile test {}:\n{}", path.display(), - compile_res - .errors + errors .iter() .map(|err| err.to_string()) .collect::>() @@ -390,18 +390,19 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>, verbose: bool) -> R } // Compile to ASM. - let asm_result = compile_ir_to_asm(&ir, None); + let handler = Handler::default(); + let asm_result = compile_ir_to_asm(&handler, &ir, None); + let (errors, _warnings) = handler.consume(); - if !asm_result.is_ok() { + if asm_result.is_err() || !errors.is_empty() { println!("Errors when compiling {test_file_name} IR to ASM:\n"); - for e in asm_result.errors { + for e in errors { println!("{e}\n"); } panic!(); }; let asm_output = asm_result - .value .map(|asm| format!("{asm}")) .expect("Failed to stringify ASM for {test_file_name}."); @@ -513,8 +514,8 @@ fn compile_core(build_target: BuildTarget, engines: &Engines) -> namespace::Modu } }; - match res.value { - Some(typed_program) if res.is_ok() => { + match res.0 { + Some(typed_program) => { // Create a module for core and copy the compiled modules into it. Unfortunately we // can't get mutable access to move them out so they're cloned. let core_module = typed_program.root.namespace.submodules().into_iter().fold( @@ -531,7 +532,8 @@ fn compile_core(build_target: BuildTarget, engines: &Engines) -> namespace::Modu std_module } _ => { - for err in res.errors { + let (errors, _warnings) = res.1.consume(); + for err in errors { println!("{err:?}"); } panic!("Failed to compile sway-lib-core for IR tests.");