diff --git a/Cargo.lock b/Cargo.lock index 29d76601adb..c2e15c22b28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5521,6 +5521,7 @@ dependencies = [ "num-bigint", "num-traits", "serde", + "sway-error", "sway-types", ] @@ -5569,11 +5570,8 @@ dependencies = [ name = "sway-error" version = "0.42.1" dependencies = [ - "extension-trait", - "num-bigint", "num-traits", "smallvec", - "sway-ast", "sway-types", "thiserror", ] diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index c3fdfd1159b..dcbcfd39b00 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -1800,8 +1800,8 @@ pub fn compile( Ok(programs) => programs, }; let typed_program = match programs.typed.as_ref() { - None => return fail(handler), - Some(typed_program) => typed_program, + Err(_) => return fail(handler), + Ok(typed_program) => typed_program, }; if profile.print_ast { @@ -1813,7 +1813,7 @@ pub fn compile( let namespace = typed_program.root.namespace.clone().into(); - if handler.has_error() { + if handler.has_errors() { return fail(handler); } @@ -1893,7 +1893,7 @@ pub fn compile( metrics ); - let errored = handler.has_error() || (handler.has_warning() && profile.error_on_warnings); + let errored = handler.has_errors() || (handler.has_warnings() && profile.error_on_warnings); let compiled = match bc_res { Ok(compiled) if !errored => compiled, @@ -2663,7 +2663,7 @@ pub fn check( }; match programs.typed.as_ref() { - Some(typed_program) => { + Ok(typed_program) => { if let TreeType::Library = typed_program.kind.tree_type() { let mut namespace = typed_program.root.namespace.clone(); namespace.name = Some(Ident::new_no_span(pkg.name.clone())); @@ -2681,7 +2681,7 @@ pub fn check( source_map.insert_dependency(manifest.dir()); } - None => { + Err(_) => { results.push((programs_res.ok(), handler)); return Ok(results); } diff --git a/forc-plugins/forc-doc/src/main.rs b/forc-plugins/forc-doc/src/main.rs index 11a091bee2b..dedfd9d71fd 100644 --- a/forc-plugins/forc-doc/src/main.rs +++ b/forc-plugins/forc-doc/src/main.rs @@ -109,7 +109,7 @@ pub fn main() -> Result<()> { 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.and_then(|programs| programs.typed) { + let ty_program = match compile_result.and_then(|programs| programs.typed.ok()) { Some(ty_program) => ty_program, _ => bail!( "documentation could not be built from manifest located at '{}'", @@ -130,7 +130,7 @@ pub fn main() -> Result<()> { let ty_program = match compile_results .pop() .and_then(|(programs, _handler)| programs) - .and_then(|p| p.typed) + .and_then(|p| p.typed.ok()) { Some(ty_program) => ty_program, _ => bail!( diff --git a/forc/src/ops/forc_check.rs b/forc/src/ops/forc_check.rs index 5e8485edac9..973d7e86a99 100644 --- a/forc/src/ops/forc_check.rs +++ b/forc/src/ops/forc_check.rs @@ -38,6 +38,6 @@ pub fn check(command: CheckCommand, engines: &Engines) -> Result<(Option), + Error(Box<[Span]>, #[serde(skip_serializing)] ErrorEmitted), Path(PathExpr), Literal(Literal), AbiCast { @@ -188,7 +190,7 @@ pub enum Expr { impl Spanned for Expr { fn span(&self) -> Span { match self { - Expr::Error(spans) => spans.iter().cloned().reduce(Span::join).unwrap(), + Expr::Error(spans, _) => spans.iter().cloned().reduce(Span::join).unwrap(), Expr::Path(path_expr) => path_expr.span(), Expr::Literal(literal) => literal.span(), Expr::AbiCast { abi_token, args } => Span::join(abi_token.span(), args.span()), diff --git a/sway-ast/src/pattern.rs b/sway-ast/src/pattern.rs index dd173f5f38b..1b095aadea1 100644 --- a/sway-ast/src/pattern.rs +++ b/sway-ast/src/pattern.rs @@ -1,3 +1,5 @@ +use sway_error::handler::ErrorEmitted; + use crate::priv_prelude::*; #[derive(Clone, Debug, Serialize)] @@ -29,7 +31,7 @@ pub enum Pattern { }, Tuple(Parens>), // to handle parser recovery: Error represents an incomplete Constructor - Error(Box<[Span]>), + Error(Box<[Span]>, #[serde(skip_serializing)] ErrorEmitted), } impl Spanned for Pattern { @@ -59,7 +61,7 @@ impl Spanned for Pattern { Pattern::Constructor { path, args } => Span::join(path.span(), args.span()), Pattern::Struct { path, fields } => Span::join(path.span(), fields.span()), Pattern::Tuple(pat_tuple) => pat_tuple.span(), - Pattern::Error(spans) => spans.iter().cloned().reduce(Span::join).unwrap(), + Pattern::Error(spans, _) => spans.iter().cloned().reduce(Span::join).unwrap(), } } } diff --git a/sway-ast/src/priv_prelude.rs b/sway-ast/src/priv_prelude.rs index 764d600350c..dbd4f13b645 100644 --- a/sway-ast/src/priv_prelude.rs +++ b/sway-ast/src/priv_prelude.rs @@ -31,7 +31,7 @@ pub use { punctuated::Punctuated, statement::{Statement, StatementLet}, submodule::Submodule, - token::{Delimiter, Group, Punct, PunctKind, Spacing, TokenStream, TokenTree}, + token::{Group, Punct, Spacing, TokenStream, TokenTree}, ty::Ty, where_clause::{WhereBound, WhereClause}, }, @@ -41,5 +41,8 @@ pub use { std::{ fmt, marker::PhantomData, mem, ops::ControlFlow, path::PathBuf, str::FromStr, sync::Arc, }, - sway_types::{Ident, Span, Spanned}, + sway_types::{ + ast::{Delimiter, PunctKind}, + Ident, Span, Spanned, + }, }; diff --git a/sway-ast/src/token.rs b/sway-ast/src/token.rs index 887f6a16ae4..f834ad34792 100644 --- a/sway-ast/src/token.rs +++ b/sway-ast/src/token.rs @@ -6,28 +6,6 @@ pub enum Spacing { Alone, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum PunctKind { - Semicolon, - Colon, - ForwardSlash, - Comma, - Star, - Add, - Sub, - LessThan, - GreaterThan, - Equals, - Dot, - Bang, - Percent, - Ampersand, - Caret, - Pipe, - Underscore, - Sharp, -} - #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)] pub struct Punct { pub span: Span, @@ -41,31 +19,6 @@ impl Spanned for Punct { } } -impl PunctKind { - pub fn as_char(&self) -> char { - match self { - PunctKind::Semicolon => ';', - PunctKind::Colon => ':', - PunctKind::ForwardSlash => '/', - PunctKind::Comma => ',', - PunctKind::Star => '*', - PunctKind::Add => '+', - PunctKind::Sub => '-', - PunctKind::LessThan => '<', - PunctKind::GreaterThan => '>', - PunctKind::Equals => '=', - PunctKind::Dot => '.', - PunctKind::Bang => '!', - PunctKind::Percent => '%', - PunctKind::Ampersand => '&', - PunctKind::Caret => '^', - PunctKind::Pipe => '|', - PunctKind::Underscore => '_', - PunctKind::Sharp => '#', - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)] pub struct GenericGroup { pub delimiter: Delimiter, @@ -82,30 +35,6 @@ impl Spanned for GenericGroup { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Delimiter { - Parenthesis, - Brace, - Bracket, -} - -impl Delimiter { - pub fn as_open_char(self) -> char { - match self { - Delimiter::Parenthesis => '(', - Delimiter::Brace => '{', - Delimiter::Bracket => '[', - } - } - pub fn as_close_char(self) -> char { - match self { - Delimiter::Parenthesis => ')', - Delimiter::Brace => '}', - Delimiter::Bracket => ']', - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)] pub enum CommentKind { /// A newlined comment is a comment with a preceding newline before another token. diff --git a/sway-core/src/abi_generation/evm_abi.rs b/sway-core/src/abi_generation/evm_abi.rs index ed5fc5af0fb..e5976456815 100644 --- a/sway-core/src/abi_generation/evm_abi.rs +++ b/sway-core/src/abi_generation/evm_abi.rs @@ -105,7 +105,7 @@ pub fn abi_str(type_info: &TypeInfo, type_engine: &TypeEngine, decl_engine: &Dec B256 => "uint256".into(), Numeric => "u64".into(), // u64 is the default Contract => "contract".into(), - ErrorRecovery => "unknown due to error".into(), + ErrorRecovery(_) => "unknown due to error".into(), Enum(decl_ref) => { let decl = decl_engine.get_enum(decl_ref); format!("enum {}", decl.call_path.suffix) diff --git a/sway-core/src/abi_generation/fuel_abi.rs b/sway-core/src/abi_generation/fuel_abi.rs index 30d59b0a8dd..0c1af316de2 100644 --- a/sway-core/src/abi_generation/fuel_abi.rs +++ b/sway-core/src/abi_generation/fuel_abi.rs @@ -806,7 +806,7 @@ impl TypeInfo { B256 => "b256".into(), Numeric => "u64".into(), // u64 is the default Contract => "contract".into(), - ErrorRecovery => "unknown due to error".into(), + ErrorRecovery(_) => "unknown due to error".into(), Enum(decl_ref) => { let decl = decl_engine.get_enum(decl_ref); format!("enum {}", call_path_display(ctx, &decl.call_path)) diff --git a/sway-core/src/asm_generation/fuel/checks.rs b/sway-core/src/asm_generation/fuel/checks.rs index 36c18a0c6d6..fa6aa6d7c9b 100644 --- a/sway-core/src/asm_generation/fuel/checks.rs +++ b/sway-core/src/asm_generation/fuel/checks.rs @@ -27,42 +27,36 @@ pub(crate) fn check_script_opcodes( ops: &[AllocatedOp], ) -> Result<(), ErrorEmitted> { use AllocatedOpcode::*; - let mut error_emitted = None; - for op in ops { - match op.opcode { - GM(_, VirtualImmediate18 { value: 1..=2 }) => { - error_emitted = Some(handler.emit_err(CompileError::GMFromExternalContext { - span: get_op_span(op), - })); - } - MINT(..) => { - error_emitted = Some(handler.emit_err(CompileError::MintFromExternalContext { - span: get_op_span(op), - })); - } - BURN(..) => { - error_emitted = Some(handler.emit_err(CompileError::BurnFromExternalContext { - span: get_op_span(op), - })); - } - SWW(..) | SRW(..) | SRWQ(..) | SWWQ(..) => { - error_emitted = Some(handler.emit_err( - CompileError::ContractStorageFromExternalContext { + // Abort compilation because the finalized asm contains opcodes invalid to a script. + // Preemptively avoids the creation of scripts with opcodes not allowed at runtime. + handler.scope(|handler| { + for op in ops { + match op.opcode { + GM(_, VirtualImmediate18 { value: 1..=2 }) => { + handler.emit_err(CompileError::GMFromExternalContext { + span: get_op_span(op), + }); + } + MINT(..) => { + handler.emit_err(CompileError::MintFromExternalContext { + span: get_op_span(op), + }); + } + BURN(..) => { + handler.emit_err(CompileError::BurnFromExternalContext { span: get_op_span(op), - }, - )); + }); + } + SWW(..) | SRW(..) | SRWQ(..) | SWWQ(..) => { + handler.emit_err(CompileError::ContractStorageFromExternalContext { + span: get_op_span(op), + }); + } + _ => (), } - _ => (), } - } - - 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(err) - } else { Ok(()) - } + }) } /// Checks if an opcode is one that cannot be executed from within a predicate. @@ -88,54 +82,49 @@ pub(crate) fn check_predicate_opcodes( ) -> Result<(), ErrorEmitted> { use AllocatedOpcode::*; - let mut error_emitted = None; - - for op in ops.iter() { - 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"), - 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 }) => { - error_emitted = Some(handler.emit_err(CompileError::GMFromExternalContext { + // Abort compilation because the finalized asm contains opcodes invalid to a predicate. + // Preemptively avoids the creation of predicates with opcodes not allowed at runtime. + handler.scope(|handler| { + for op in ops.iter() { + let invalid_opcode = |name_str: &str| { + handler.emit_err(CompileError::InvalidOpcodeFromPredicate { + opcode: name_str.to_string(), span: get_op_span(op), - })); - } - 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 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(err) - } else { + }); + }; + match op.opcode.clone() { + 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 }) => { + handler.emit_err(CompileError::GMFromExternalContext { + span: get_op_span(op), + }); + } + 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"), + _ => (), + }; + } Ok(()) - } + }) } fn get_op_span(op: &AllocatedOp) -> Span { diff --git a/sway-core/src/control_flow_analysis/analyze_return_paths.rs b/sway-core/src/control_flow_analysis/analyze_return_paths.rs index 3207f93ac61..9e5a1812eda 100644 --- a/sway-core/src/control_flow_analysis/analyze_return_paths.rs +++ b/sway-core/src/control_flow_analysis/analyze_return_paths.rs @@ -217,7 +217,7 @@ fn connect_declaration<'eng: 'cfg, 'cfg>( connect_impl_trait(engines, &trait_name, graph, &items, entry_node)?; Ok(leaves.to_vec()) } - ty::TyDecl::ErrorRecovery(_) => Ok(leaves.to_vec()), + ty::TyDecl::ErrorRecovery(..) => Ok(leaves.to_vec()), } } 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 ffdc94bc8f6..bd831cba92e 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -564,7 +564,7 @@ fn connect_declaration<'eng: 'cfg, 'cfg>( connect_type_alias_declaration(engines, &type_alias, graph, entry_node)?; Ok(leaves.to_vec()) } - ty::TyDecl::ErrorRecovery(_) | ty::TyDecl::GenericTypeForFunctionScope(_) => { + ty::TyDecl::ErrorRecovery(..) | ty::TyDecl::GenericTypeForFunctionScope(_) => { Ok(leaves.to_vec()) } } @@ -2252,7 +2252,7 @@ fn allow_dead_code_ast_node(decl_engine: &DeclEngine, node: &ty::TyAstNode) -> b ty::TyDecl::ImplTrait { .. } => false, ty::TyDecl::AbiDecl { .. } => false, ty::TyDecl::GenericTypeForFunctionScope { .. } => false, - ty::TyDecl::ErrorRecovery(_) => false, + ty::TyDecl::ErrorRecovery(..) => false, ty::TyDecl::StorageDecl { .. } => false, }, ty::TyAstNodeContent::Expression(_) => false, diff --git a/sway-core/src/ir_generation/compile.rs b/sway-core/src/ir_generation/compile.rs index 0e655e43d9b..42192992a1c 100644 --- a/sway-core/src/ir_generation/compile.rs +++ b/sway-core/src/ir_generation/compile.rs @@ -294,7 +294,7 @@ fn compile_declarations( | ty::TyDecl::GenericTypeForFunctionScope { .. } | ty::TyDecl::StorageDecl { .. } | ty::TyDecl::TypeAliasDecl { .. } - | ty::TyDecl::ErrorRecovery(_) => (), + | ty::TyDecl::ErrorRecovery(..) => (), } } Ok(()) diff --git a/sway-core/src/ir_generation/convert.rs b/sway-core/src/ir_generation/convert.rs index 476973025fc..6dfe2955c7c 100644 --- a/sway-core/src/ir_generation/convert.rs +++ b/sway-core/src/ir_generation/convert.rs @@ -164,7 +164,7 @@ fn convert_resolved_type( TypeInfo::UnknownGeneric { .. } => reject_type!("Generic"), TypeInfo::Placeholder(_) => reject_type!("Placeholder"), TypeInfo::TypeParam(_) => reject_type!("TypeParam"), - TypeInfo::ErrorRecovery => reject_type!("Error recovery"), + TypeInfo::ErrorRecovery(_) => reject_type!("Error recovery"), TypeInfo::Storage { .. } => reject_type!("Storage"), }) } diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 675e857c5c0..b27224b6895 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -3,6 +3,7 @@ use crate::{ type_system::TypeBinding, TypeArgument, TypeInfo, }; +use sway_error::handler::ErrorEmitted; use sway_types::{ident::Ident, Span, Spanned}; mod asm; @@ -171,7 +172,7 @@ pub enum ExpressionKind { /// Used for parser recovery when we cannot form a more specific node. /// The list of `Span`s are for consumption by the LSP and are, /// when joined, the same as that stored in `expr.span`. - Error(Box<[Span]>), + Error(Box<[Span]>, ErrorEmitted), Literal(Literal), /// An ambiguous path where we don't know until type checking whether this /// is a free function call, an enum variant or a UFCS (Rust term) style associated function call. diff --git a/sway-core/src/language/parsed/expression/scrutinee.rs b/sway-core/src/language/parsed/expression/scrutinee.rs index f5a84a0d6de..2def9dc89df 100644 --- a/sway-core/src/language/parsed/expression/scrutinee.rs +++ b/sway-core/src/language/parsed/expression/scrutinee.rs @@ -3,6 +3,7 @@ use crate::{ TypeInfo, }; +use sway_error::handler::ErrorEmitted; use sway_types::{ident::Ident, span::Span, Spanned}; /// A [Scrutinee] is on the left-hand-side of a pattern, and dictates whether or @@ -44,6 +45,7 @@ pub enum Scrutinee { // this is to handle parser recovery Error { spans: Box<[Span]>, + err: ErrorEmitted, }, } @@ -71,7 +73,7 @@ impl Spanned for Scrutinee { Scrutinee::StructScrutinee { span, .. } => span.clone(), Scrutinee::EnumScrutinee { span, .. } => span.clone(), Scrutinee::Tuple { span, .. } => span.clone(), - Scrutinee::Error { spans } => spans.iter().cloned().reduce(Span::join).unwrap(), + Scrutinee::Error { spans, .. } => spans.iter().cloned().reduce(Span::join).unwrap(), } } } diff --git a/sway-core/src/language/programs.rs b/sway-core/src/language/programs.rs index 3797994fdd5..2dce991d983 100644 --- a/sway-core/src/language/programs.rs +++ b/sway-core/src/language/programs.rs @@ -1,14 +1,20 @@ +use sway_error::handler::ErrorEmitted; + use super::{lexed::LexedProgram, parsed::ParseProgram, ty::TyProgram}; /// Contains the lexed, parsed, and typed compilation stages of a program. pub struct Programs { pub lexed: LexedProgram, pub parsed: ParseProgram, - pub typed: Option, + pub typed: Result, } impl Programs { - pub fn new(lexed: LexedProgram, parsed: ParseProgram, typed: Option) -> Programs { + pub fn new( + lexed: LexedProgram, + parsed: ParseProgram, + typed: Result, + ) -> Programs { Programs { lexed, parsed, diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index b367ec364ec..c3cb1addffb 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -31,7 +31,7 @@ pub enum TyDecl { // If type parameters are defined for a function, they are put in the namespace just for // the body of that function. GenericTypeForFunctionScope(GenericTypeForFunctionScope), - ErrorRecovery(Span), + ErrorRecovery(Span, ErrorEmitted), StorageDecl(StorageDecl), TypeAliasDecl(TypeAliasDecl), } @@ -225,7 +225,7 @@ impl PartialEqWithEngines for TyDecl { type_id: yti, }), ) => xn == yn && type_engine.get(*xti).eq(&type_engine.get(*yti), engines), - (TyDecl::ErrorRecovery(x), TyDecl::ErrorRecovery(y)) => x == y, + (TyDecl::ErrorRecovery(x, _), TyDecl::ErrorRecovery(y, _)) => x == y, _ => false, } } @@ -279,7 +279,7 @@ impl HashWithEngines for TyDecl { name.hash(state); type_engine.get(*type_id).hash(state, engines); } - TyDecl::ErrorRecovery(_) => {} + TyDecl::ErrorRecovery(..) => {} } } } @@ -328,7 +328,7 @@ impl SubstTypes for TyDecl { | TyDecl::ConstantDecl(_) | TyDecl::StorageDecl(_) | TyDecl::GenericTypeForFunctionScope(_) - | TyDecl::ErrorRecovery(_) => (), + | TyDecl::ErrorRecovery(..) => (), } } } @@ -365,7 +365,7 @@ impl ReplaceSelfType for TyDecl { | TyDecl::ConstantDecl(_) | TyDecl::StorageDecl(_) | TyDecl::GenericTypeForFunctionScope(_) - | TyDecl::ErrorRecovery(_) => (), + | TyDecl::ErrorRecovery(..) => (), } } } @@ -405,7 +405,7 @@ impl Spanned for TyDecl { TyDecl::GenericTypeForFunctionScope(GenericTypeForFunctionScope { name, .. }) => { name.span() } - TyDecl::ErrorRecovery(span) => span.clone(), + TyDecl::ErrorRecovery(span, _) => span.clone(), } } } @@ -531,7 +531,7 @@ impl CollectTypesMetadata for TyDecl { return Ok(vec![]); } } - TyDecl::ErrorRecovery(_) + TyDecl::ErrorRecovery(..) | TyDecl::StorageDecl(_) | TyDecl::TraitDecl(_) | TyDecl::StructDecl(_) @@ -562,7 +562,7 @@ impl GetDeclIdent for TyDecl { TyDecl::EnumVariantDecl(EnumVariantDecl { variant_name, .. }) => { Some(variant_name.clone()) } - TyDecl::ErrorRecovery(_) => None, + TyDecl::ErrorRecovery(..) => None, TyDecl::StorageDecl(_) => None, } } @@ -591,7 +591,7 @@ impl TyDecl { .get(ty.type_id) .expect_enum(handler, engines, "", &span) } - TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + TyDecl::ErrorRecovery(_, err) => Err(*err), decl => Err(handler.emit_err(CompileError::DeclIsNotAnEnum { actually: decl.friendly_type_name().to_string(), span: decl.span(), @@ -621,7 +621,7 @@ impl TyDecl { .get(ty.type_id) .expect_struct(handler, engines, &span) } - TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + TyDecl::ErrorRecovery(_, err) => Err(*err), decl => Err(handler.emit_err(CompileError::DeclIsNotAStruct { actually: decl.friendly_type_name().to_string(), span: decl.span(), @@ -643,7 +643,7 @@ impl TyDecl { subst_list: _, decl_span, }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), - TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + TyDecl::ErrorRecovery(_, err) => Err(*err), decl => Err(handler.emit_err(CompileError::DeclIsNotAFunction { actually: decl.friendly_type_name().to_string(), span: decl.span(), @@ -660,7 +660,7 @@ impl TyDecl { ) -> Result<&TyVariableDecl, ErrorEmitted> { match self { TyDecl::VariableDecl(decl) => Ok(decl), - TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + TyDecl::ErrorRecovery(_, err) => Err(*err), decl => Err(handler.emit_err(CompileError::DeclIsNotAVariable { actually: decl.friendly_type_name().to_string(), span: decl.span(), @@ -681,7 +681,7 @@ impl TyDecl { decl_id, decl_span, }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), - TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + TyDecl::ErrorRecovery(_, err) => Err(*err), decl => Err(handler.emit_err(CompileError::DeclIsNotAnAbi { actually: decl.friendly_type_name().to_string(), span: decl.span(), @@ -702,7 +702,7 @@ impl TyDecl { decl_id, decl_span, }) => Ok(DeclRef::new(name.clone(), *decl_id, decl_span.clone())), - TyDecl::ErrorRecovery(_) => Err(ErrorEmitted), + TyDecl::ErrorRecovery(_, err) => Err(*err), decl => Err(handler.emit_err(CompileError::DeclIsNotAConstant { actually: decl.friendly_type_name().to_string(), span: decl.span(), @@ -747,7 +747,7 @@ impl TyDecl { ImplTrait(_) => "impl trait", AbiDecl(_) => "abi", GenericTypeForFunctionScope(_) => "generic type parameter", - ErrorRecovery(_) => "error", + ErrorRecovery(_, _) => "error", StorageDecl(_) => "contract storage", TypeAliasDecl(_) => "type alias", } @@ -862,7 +862,7 @@ impl TyDecl { | TyDecl::ImplTrait(_) | TyDecl::StorageDecl(_) | TyDecl::AbiDecl(_) - | TyDecl::ErrorRecovery(_) => Visibility::Public, + | TyDecl::ErrorRecovery(_, _) => Visibility::Public, TyDecl::VariableDecl(decl) => decl.mutability.visibility(), } } diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index fbdcab7a0a4..317d506cc86 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -379,11 +379,11 @@ impl DeterministicallyAborts for TyExpression { } impl TyExpression { - pub(crate) fn error(span: Span, engines: &Engines) -> TyExpression { + pub(crate) fn error(err: ErrorEmitted, span: Span, engines: &Engines) -> TyExpression { let type_engine = engines.te(); TyExpression { expression: TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery), + return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery(err)), span, } } diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index b12812e5c54..2bad206054a 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -49,7 +49,6 @@ pub use semantic_analysis::namespace::{self, Namespace}; pub mod types; use sway_error::error::CompileError; -use sway_error::warning::CompileWarning; use sway_types::{ident::Ident, span, Spanned}; pub use type_system::*; @@ -513,7 +512,7 @@ pub fn compile_to_ast( ); handler.dedup(); - Ok(Programs::new(lexed_program, parsed_program, typed_res.ok())) + Ok(Programs::new(lexed_program, parsed_program, typed_res)) } /// Given input Sway source code, try compiling to a `CompiledAsm`, @@ -548,15 +547,15 @@ pub fn ast_to_asm( build_config: &BuildConfig, ) -> Result { let typed_program = match &programs.typed { - Some(typed_program) => typed_program, - None => return Err(ErrorEmitted), + Ok(typed_program) => typed_program, + Err(err) => return Err(*err), }; let asm = match compile_ast_to_ir_to_asm(handler, engines, typed_program, build_config) { Ok(res) => res, - Err(_) => { + Err(err) => { handler.dedup(); - return Err(ErrorEmitted); + return Err(err); } }; Ok(CompiledAsm(asm)) @@ -694,14 +693,13 @@ fn perform_control_flow_analysis( ) -> 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(()) - } else { + let rpa_res = handler.scope(|handler| { for err in rpa_errors { handler.emit_err(err); } - Err(ErrorEmitted) - }; + Ok(()) + }); + if let Ok(graph) = dca_res.clone() { graph.visualize(engines, print_graph, print_graph_url_format); } diff --git a/sway-core/src/monomorphize/gather/declaration.rs b/sway-core/src/monomorphize/gather/declaration.rs index 3c8959098fa..2f948111324 100644 --- a/sway-core/src/monomorphize/gather/declaration.rs +++ b/sway-core/src/monomorphize/gather/declaration.rs @@ -27,7 +27,7 @@ pub(crate) fn gather_from_decl( ty::TyDecl::AbiDecl(_) => todo!(), ty::TyDecl::GenericTypeForFunctionScope(_) => todo!(), ty::TyDecl::StorageDecl(_) => todo!(), - ty::TyDecl::ErrorRecovery(_) => {} + ty::TyDecl::ErrorRecovery(_, _) => {} ty::TyDecl::TypeAliasDecl(_) => todo!(), } diff --git a/sway-core/src/monomorphize/instruct/declaration.rs b/sway-core/src/monomorphize/instruct/declaration.rs index 3d64d60d8df..564aea3818a 100644 --- a/sway-core/src/monomorphize/instruct/declaration.rs +++ b/sway-core/src/monomorphize/instruct/declaration.rs @@ -27,7 +27,7 @@ pub(crate) fn instruct_decl( ty::TyDecl::AbiDecl(_) => todo!(), ty::TyDecl::GenericTypeForFunctionScope(_) => todo!(), ty::TyDecl::StorageDecl(_) => todo!(), - ty::TyDecl::ErrorRecovery(_) => {} + ty::TyDecl::ErrorRecovery(_, _) => {} ty::TyDecl::TypeAliasDecl(_) => todo!(), } Ok(()) diff --git a/sway-core/src/monomorphize/solve/solver.rs b/sway-core/src/monomorphize/solve/solver.rs index cefe90dc795..739401654ce 100644 --- a/sway-core/src/monomorphize/solve/solver.rs +++ b/sway-core/src/monomorphize/solve/solver.rs @@ -134,7 +134,7 @@ impl<'a> Solver<'a> { TypeInfo::Custom { .. } => todo!(), TypeInfo::SelfType => todo!(), TypeInfo::Numeric => todo!(), - TypeInfo::ErrorRecovery => todo!(), + TypeInfo::ErrorRecovery(_) => todo!(), TypeInfo::Array(_, _) => todo!(), TypeInfo::Storage { .. } => todo!(), TypeInfo::Alias { .. } => todo!(), 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 1f7c071b577..c9d79d2413a 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -91,13 +91,7 @@ impl ty::TyCodeBlock { } }); - 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); - } + ctx.unify_with_self(handler, block_type, &span); let typed_code_block = ty::TyCodeBlock { contents: evaluated_contents, 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 d3b5add14b9..54bb27cdee7 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -203,15 +203,91 @@ 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 Ok(superabi_method_ref) = ctx.namespace.find_method_for_type( + handler.scope(|handler| { + 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 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)) = + superabi_method.implementing_type.clone() + { + // rule out the diamond superABI hierarchy: + // it's not an error if the "conflicting" methods + // actually come from the same super-ABI + // Top + // / \ + // Left Right + // \ / + // Bottom + // if we are accumulating methods from Left and Right + // 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 { + 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(), + }, + ); + } + } + } + } + method.replace_self_type(engines, type_id); + all_items.push(TyImplItem::Fn( + ctx.engines + .de() + .insert(method.to_dummy_func(AbiMode::ImplAbiFn( + self.name.clone(), + Some(self_decl_id), + ))) + .with_parent(ctx.engines.de(), (*decl_ref.id()).into()), + )); + } + ty::TyTraitInterfaceItem::Constant(decl_ref) => { + let const_decl = decl_engine.get_constant(decl_ref); + 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(); + let _ = ctx.namespace.insert_symbol( + handler, + const_name.clone(), + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + name: const_name, + decl_id: *decl_ref.id(), + decl_span: const_decl.span.clone(), + }), + const_shadowing_mode, + ); + } + } + } + for item in items.iter() { + match item { + ty::TyTraitItem::Fn(decl_ref) => { + let mut method = decl_engine.get_function(decl_ref); + // 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 Ok(superabi_impl_method_ref) = ctx.namespace.find_method_for_type( &Handler::default(), ctx.self_type(), &[], @@ -223,137 +299,55 @@ impl ty::TyAbiDecl { ctx.engines, false, ) { - let superabi_method = - ctx.engines.de().get_function(&superabi_method_ref); + let superabi_impl_method = + ctx.engines.de().get_function(&superabi_impl_method_ref); if let Some(ty::TyDecl::AbiDecl(abi_decl)) = - superabi_method.implementing_type.clone() + superabi_impl_method.implementing_type.clone() { - // rule out the diamond superABI hierarchy: - // it's not an error if the "conflicting" methods - // actually come from the same super-ABI - // Top - // / \ - // Left Right - // \ / - // Bottom - // if we are accumulating methods from Left and Right - // to place it into Bottom we will encounter - // the same method from Top in both Left and Right + // allow the diamond superABI hierarchy if self_decl_id != abi_decl.decl_id { - 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(), - }, - )) - } - } - } - } - method.replace_self_type(engines, type_id); - all_items.push(TyImplItem::Fn( - ctx.engines - .de() - .insert(method.to_dummy_func(AbiMode::ImplAbiFn( - self.name.clone(), - Some(self_decl_id), - ))) - .with_parent(ctx.engines.de(), (*decl_ref.id()).into()), - )); - } - ty::TyTraitInterfaceItem::Constant(decl_ref) => { - let const_decl = decl_engine.get_constant(decl_ref); - 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(); - let _ = ctx.namespace.insert_symbol( - handler, - const_name.clone(), - ty::TyDecl::ConstantDecl(ty::ConstantDecl { - name: const_name, - decl_id: *decl_ref.id(), - decl_span: const_decl.span.clone(), - }), - const_shadowing_mode, - ); - } - } - } - for item in items.iter() { - match item { - ty::TyTraitItem::Fn(decl_ref) => { - let mut method = decl_engine.get_function(decl_ref); - // 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 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() - { - // allow the diamond superABI hierarchy - if self_decl_id != abi_decl.decl_id { - error_emitted = Some(handler.emit_err( - CompileError::ConflictingSuperAbiMethods { + 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(), - }, - )) + }); + } } } + method.replace_self_type(engines, type_id); + all_items.push(TyImplItem::Fn( + ctx.engines + .de() + .insert(method) + .with_parent(ctx.engines.de(), (*decl_ref.id()).into()), + )); + } + ty::TyTraitItem::Constant(decl_ref) => { + let mut const_decl = decl_engine.get_constant(decl_ref); + const_decl.replace_self_type(engines, type_id); + all_items.push(TyImplItem::Constant(ctx.engines.de().insert(const_decl))); } - method.replace_self_type(engines, type_id); - all_items.push(TyImplItem::Fn( - ctx.engines - .de() - .insert(method) - .with_parent(ctx.engines.de(), (*decl_ref.id()).into()), - )); - } - ty::TyTraitItem::Constant(decl_ref) => { - let mut const_decl = decl_engine.get_constant(decl_ref); - const_decl.replace_self_type(engines, type_id); - all_items.push(TyImplItem::Constant(ctx.engines.de().insert(const_decl))); } } - } - // Insert the methods of the ABI into the namespace. - // Specifically do not check for conflicting definitions because - // this is just a temporary namespace for type checking and - // 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. - let _ = ctx.namespace.insert_trait_implementation( - &Handler::default(), - CallPath::from(self.name.clone()), - vec![], - type_id, - &all_items, - &self.span, - Some(self.span()), - false, - ctx.engines, - ); - if let Some(err) = error_emitted { - Err(err) - } else { + // Insert the methods of the ABI into the namespace. + // Specifically do not check for conflicting definitions because + // this is just a temporary namespace for type checking and + // 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. + let _ = ctx.namespace.insert_trait_implementation( + &Handler::default(), + CallPath::from(self.name.clone()), + vec![], + type_id, + &all_items, + &self.span, + Some(self.span()), + false, + ctx.engines, + ); 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 ea1a5627b9c..6f441932a6d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs @@ -41,7 +41,7 @@ impl ty::TyConstantDecl { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); let mut ctx = ctx .by_ref() @@ -65,7 +65,7 @@ impl ty::TyConstantDecl { } let value = - result.unwrap_or_else(|_| ty::TyExpression::error(name.span(), engines)); + result.unwrap_or_else(|err| ty::TyExpression::error(err, name.span(), engines)); Some(value) } 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 c5c1a6baa4b..d41dd069ff2 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -33,7 +33,9 @@ impl ty::TyDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| { + type_engine.insert(engines, TypeInfo::ErrorRecovery(err)) + }); let mut ctx = ctx .with_type_annotation(type_ascription.type_id) .with_help_text( @@ -41,7 +43,8 @@ impl ty::TyDecl { with the assigned expression's type.", ); let result = ty::TyExpression::type_check(handler, ctx.by_ref(), body); - let body = result.unwrap_or_else(|_| ty::TyExpression::error(name.span(), engines)); + let body = + result.unwrap_or_else(|err| ty::TyExpression::error(err, 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 @@ -65,7 +68,7 @@ impl ty::TyDecl { let span = decl.span.clone(); let const_decl = match ty::TyConstantDecl::type_check(handler, ctx.by_ref(), decl) { Ok(res) => res, - Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; let typed_const_decl: ty::TyDecl = decl_engine.insert(const_decl.clone()).into(); ctx.insert_symbol(handler, const_decl.name().clone(), typed_const_decl.clone())?; @@ -75,7 +78,7 @@ impl ty::TyDecl { let span = decl.span.clone(); let enum_decl = match ty::TyEnumDecl::type_check(handler, ctx.by_ref(), decl) { Ok(res) => res, - Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; let call_path = enum_decl.call_path.clone(); let decl: ty::TyDecl = decl_engine.insert(enum_decl).into(); @@ -94,7 +97,7 @@ impl ty::TyDecl { false, ) { Ok(res) => res, - Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; let name = fn_decl.name.clone(); let decl: ty::TyDecl = decl_engine.insert(fn_decl).into(); @@ -106,7 +109,7 @@ impl ty::TyDecl { 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)), + Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; let name = trait_decl.name.clone(); @@ -148,7 +151,7 @@ impl ty::TyDecl { match ty::TyImplTrait::type_check_impl_trait(handler, ctx.by_ref(), impl_trait) { Ok(res) => res, - Err(_) => return Ok(ty::TyDecl::ErrorRecovery(span)), + Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; // if this ImplTrait implements a trait and not an ABI, // we insert its methods into the context @@ -191,7 +194,7 @@ impl ty::TyDecl { 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)), + Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; ctx.namespace.insert_trait_implementation( handler, @@ -217,8 +220,8 @@ impl ty::TyDecl { let span = decl.span.clone(); let decl = match ty::TyStructDecl::type_check(handler, ctx.by_ref(), decl) { Ok(res) => res, - Err(_) => { - return Ok(ty::TyDecl::ErrorRecovery(span)); + Err(err) => { + return Ok(ty::TyDecl::ErrorRecovery(span, err)); } }; let call_path = decl.call_path.clone(); @@ -232,8 +235,8 @@ impl ty::TyDecl { 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)); + Err(err) => { + return Ok(ty::TyDecl::ErrorRecovery(span, err)); } }; let name = abi_decl.name.clone(); @@ -333,7 +336,9 @@ impl ty::TyDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| { + type_engine.insert(engines, TypeInfo::ErrorRecovery(err)) + }); // create the type alias decl using the resolved type above let decl = ty::TyTypeAliasDecl { 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 4cbcee96464..c42d6eba69a 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -75,7 +75,7 @@ impl ty::TyEnumVariant { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); Ok(ty::TyEnumVariant { name: variant.name.clone(), type_argument, 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 606675c6427..de3638c99a7 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -70,21 +70,17 @@ impl ty::TyFunctionDecl { // 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( - match ty::TyFunctionParameter::type_check(handler, ctx.by_ref(), parameter) { - Ok(val) => val, - Err(err) => { - error_emitted = Some(err); - continue; - } - }, - ); - } - if let Some(err) = error_emitted { - return Err(err); - } + handler.scope(|handler| { + for parameter in parameters.into_iter() { + new_parameters.push( + match ty::TyFunctionParameter::type_check(handler, ctx.by_ref(), parameter) { + Ok(val) => val, + Err(_) => continue, + }, + ); + } + Ok(()) + })?; // type check the return type return_type.type_id = ctx @@ -95,7 +91,7 @@ impl ty::TyFunctionDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); // type check the function body // @@ -107,10 +103,10 @@ 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); - ty::TyCodeBlock::type_check(handler, ctx, body).unwrap_or_else(|_| { + ty::TyCodeBlock::type_check(handler, ctx, body).unwrap_or_else(|err| { ( ty::TyCodeBlock { contents: vec![] }, - type_engine.insert(engines, TypeInfo::ErrorRecovery), + type_engine.insert(engines, TypeInfo::ErrorRecovery(err)), ) }) }; @@ -175,30 +171,21 @@ fn unify_return_statements( ) -> Result<(), ErrorEmitted> { let type_engine = ctx.engines.te(); - let mut error_emitted = None; - - for stmt in return_statements.iter() { - 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)); + handler.scope(|handler| { + for stmt in return_statements.iter() { + type_engine.unify_with_self( + handler, + ctx.engines(), + stmt.return_type, + return_type, + ctx.self_type(), + &stmt.span, + "Return statement must return the declared function return type.", + None, + ); } - } - if let Some(err) = error_emitted { - Err(err) - } else { Ok(()) - } + }) } #[test] 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 57e7fb0b26e..35b5e56d448 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 @@ -35,7 +35,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); type_argument.type_id.check_type_parameter_bounds( handler, @@ -91,7 +91,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); let typed_parameter = ty::TyFunctionParameter { name, 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 0ff4a83b8a6..88f6fcf9e04 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 @@ -292,53 +292,46 @@ impl ty::TyImplTrait { // 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 = 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 = - match ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl) { + handler.scope(|handler| { + for item in items.into_iter() { + match item { + ImplItem::Fn(fn_decl) => { + 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; - } + Err(_) => continue, }; - let decl_ref = decl_engine.insert(const_decl); - new_items.push(TyImplItem::Constant(decl_ref.clone())); - - 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(), - }), - )?; + new_items.push(TyImplItem::Fn(decl_engine.insert(fn_decl))); + } + ImplItem::Constant(const_decl) => { + let const_decl = + match ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl) + { + Ok(res) => res, + Err(_) => continue, + }; + let decl_ref = decl_engine.insert(const_decl); + new_items.push(TyImplItem::Constant(decl_ref.clone())); + + 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 let Some(err) = error_emitted { - return Err(err); - } + Ok(()) + })?; let impl_trait = ty::TyImplTrait { impl_type_parameters: new_impl_type_parameters, @@ -559,11 +552,9 @@ fn type_check_trait_implementation( } } - let mut error_emitted = None; - - // check that the implementation checklist is complete - if !method_checklist.is_empty() { - error_emitted = Some( + handler.scope(|handler| { + // check that the implementation checklist is complete + if !method_checklist.is_empty() { handler.emit_err(CompileError::MissingInterfaceSurfaceMethods { span: block_span.clone(), missing_functions: method_checklist @@ -571,12 +562,10 @@ fn type_check_trait_implementation( .map(|ident| ident.as_str().to_string()) .collect::>() .join("\n"), - }), - ); - } + }); + } - if !constant_checklist.is_empty() { - error_emitted = Some( + if !constant_checklist.is_empty() { handler.emit_err(CompileError::MissingInterfaceSurfaceConstants { span: block_span.clone(), missing_constants: constant_checklist @@ -584,15 +573,11 @@ fn type_check_trait_implementation( .map(|ident| ident.as_str().to_string()) .collect::>() .join("\n"), - }), - ); - } + }); + } - if let Some(err) = error_emitted { - Err(err) - } else { Ok(all_items_refs) - } + }) } #[allow(clippy::too_many_arguments)] @@ -628,7 +613,7 @@ fn type_check_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()) { + if impld_item_refs.contains_key(&impl_method.name) { return Err( handler.emit_err(CompileError::MultipleDefinitionsOfFunction { name: impl_method.name.clone(), @@ -670,43 +655,37 @@ fn type_check_impl_method( )); } - 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 - .parameters - .iter_mut() - .zip(&mut impl_method.parameters) - { - // TODO use trait constraints as part of the type here to - // 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 { - error_emitted = Some( + handler.scope(|handler| { + // 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 + .parameters + .iter_mut() + .zip(&mut impl_method.parameters) + { + // TODO use trait constraints as part of the type here to + // 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 { 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 - { - error_emitted = Some( + // 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 + { 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, - ) { - error_emitted = Some( + if !type_engine.get(impl_method_param.type_argument.type_id).eq( + &type_engine.get(impl_method_signature_param.type_argument.type_id), + engines, + ) { handler.emit_err(CompileError::MismatchedTypeInInterfaceSurface { interface_name: interface_name(), span: impl_method_param.type_argument.span.clone(), @@ -717,16 +696,14 @@ fn type_check_impl_method( expected: engines .help_out(impl_method_signature_param.type_argument.type_id) .to_string(), - }), - ); - continue; + }); + continue; + } } - } - // 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 { - error_emitted = Some( + // 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 { handler.emit_err(if impl_method_signature.purity == Purity::Pure { CompileError::TraitDeclPureImplImpure { fn_name: impl_method.name.clone(), @@ -741,83 +718,79 @@ fn type_check_impl_method( attrs: impl_method_signature.purity.to_attribute_syntax(), span: impl_method.span.clone(), } - }), - ); - } + }); + } - // check there is no mismatch of payability attributes - // between the method signature and the method implementation - use crate::transform::AttributeKind::Payable; - let impl_method_signature_payable = impl_method_signature.attributes.contains_key(&Payable); - let impl_method_payable = impl_method.attributes.contains_key(&Payable); - match (impl_method_signature_payable, impl_method_payable) { - (true, false) => - // implementation does not have payable attribute - { - 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(), - })); + // check there is no mismatch of payability attributes + // between the method signature and the method implementation + use crate::transform::AttributeKind::Payable; + let impl_method_signature_payable = impl_method_signature.attributes.contains_key(&Payable); + let impl_method_payable = impl_method.attributes.contains_key(&Payable); + match (impl_method_signature_payable, impl_method_payable) { + (true, false) => + // implementation does not have payable attribute + { + 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 + { + 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 } - (false, true) => - // implementation has extra payable attribute, not mentioned by signature - { - 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(), - })); + + if !type_engine.get(impl_method.return_type.type_id).eq( + &type_engine.get(impl_method_signature.return_type.type_id), + engines, + ) { + 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(), + }), + ); } - (true, true) | (false, false) => (), // no payability mismatch - } - if !type_engine.get(impl_method.return_type.type_id).eq( - &type_engine.get(impl_method_signature.return_type.type_id), - engines, - ) { - 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 + // so that in-line monomorphization can complete. + // + // We also need to add impl type parameters to the method's type + // parameters so the type constraints are correctly applied to the method. + // + // NOTE: this is a semi-hack that is used to force monomorphization of + // trait methods that contain a generic defined in the parent impl... + // without stuffing the generic into the method's type parameters, its + // not currently possible to monomorphize on that generic at function + // application time. + impl_method.type_parameters.append( + &mut impl_type_parameters + .iter() + .cloned() + .map(|mut t| { + t.is_from_parent = true; + t + }) + .collect::>(), ); - } - - // We need to add impl type parameters to the method's type parameters - // so that in-line monomorphization can complete. - // - // We also need to add impl type parameters to the method's type - // parameters so the type constraints are correctly applied to the method. - // - // NOTE: this is a semi-hack that is used to force monomorphization of - // trait methods that contain a generic defined in the parent impl... - // without stuffing the generic into the method's type parameters, its - // not currently possible to monomorphize on that generic at function - // application time. - impl_method.type_parameters.append( - &mut impl_type_parameters - .iter() - .cloned() - .map(|mut t| { - t.is_from_parent = true; - t - }) - .collect::>(), - ); - if let Some(err) = error_emitted { - Err(err) - } else { Ok(impl_method) - } + }) } fn type_check_const_decl( @@ -972,22 +945,17 @@ 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() { - error_emitted = Some( + handler.scope(|handler| { + // create an error for all of the leftover generics + for (k, v) in defined_generics.into_iter() { handler.emit_err(CompileError::UnconstrainedGenericParameter { ty: format!("{k}"), span: v, - }), - ); - } + }); + } - if let Some(err) = error_emitted { - Err(err) - } else { Ok(()) - } + }) } fn handle_supertraits( @@ -1001,79 +969,72 @@ fn handle_supertraits( 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() { - 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; - } + handler.scope(|handler| { + 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() { + 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(handler, &supertrait.name) - .ok() - .cloned() - { - Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { - let trait_decl = decl_engine.get_trait(&decl_id); - - // 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() { - error_emitted = Some(handler.emit_err(CompileError::Unimplemented( - "Using generic traits as supertraits is not supported yet.", - supertrait.name.span(), - ))); - continue; + match ctx + .namespace + .resolve_call_path(handler, &supertrait.name) + .ok() + .cloned() + { + Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { + let trait_decl = decl_engine.get_trait(&decl_id); + + // 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() { + handler.emit_err(CompileError::Unimplemented( + "Using generic traits as supertraits is not supported yet.", + supertrait.name.span(), + )); + continue; + } + + // Retrieve the interface surface and implemented method ids for + // this trait. + let (trait_interface_surface_items_ids, trait_impld_item_refs) = trait_decl + .retrieve_interface_surface_and_implemented_items_for_type( + ctx.by_ref(), + self_type, + &supertrait.name, + ); + interface_surface_item_ids.extend(trait_interface_surface_items_ids); + impld_item_refs.extend(trait_impld_item_refs); + + // Retrieve the interface surfaces and implemented methods for + // the supertraits of this type. + 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(_) => 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 + } + _ => { + handler.emit_err(CompileError::TraitNotFound { + name: supertrait.name.to_string(), + span: supertrait.name.span(), + }); } - - // Retrieve the interface surface and implemented method ids for - // this trait. - let (trait_interface_surface_items_ids, trait_impld_item_refs) = trait_decl - .retrieve_interface_surface_and_implemented_items_for_type( - ctx.by_ref(), - self_type, - &supertrait.name, - ); - interface_surface_item_ids.extend(trait_interface_surface_items_ids); - impld_item_refs.extend(trait_impld_item_refs); - - // Retrieve the interface surfaces and implemented methods for - // the supertraits of this type. - 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 - } - _ => { - error_emitted = Some(handler.emit_err(CompileError::TraitNotFound { - name: supertrait.name.to_string(), - span: supertrait.name.span(), - })) } } - } - if let Some(err) = error_emitted { - Err(err) - } else { 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 bfa9975814e..b1d7dfb4b74 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs @@ -23,32 +23,26 @@ impl ty::TyStorageDecl { md_mgr: &mut MetadataManager, module: Module, ) -> Result, ErrorEmitted> { - let mut error_emitted = None; - let storage_slots = self - .fields - .iter() - .enumerate() - .map(|(i, f)| { - f.get_initialized_storage_slots( - engines, - context, - md_mgr, - module, - &StateIndex::new(i), - ) - }) - .filter_map(|s| { - s.map_err(|e| error_emitted = Some(handler.emit_err(e))) - .ok() - }) - .flatten() - .collect::>(); + handler.scope(|handler| { + let storage_slots = self + .fields + .iter() + .enumerate() + .map(|(i, f)| { + f.get_initialized_storage_slots( + engines, + context, + md_mgr, + module, + &StateIndex::new(i), + ) + }) + .filter_map(|s| s.map_err(|e| handler.emit_err(e)).ok()) + .flatten() + .collect::>(); - 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 af2dc7021c4..e7d418d1e68 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -71,7 +71,7 @@ impl ty::TyStructField { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery(err))); let field = ty::TyStructField { name: field.name, span: field.span, 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 cd9c597b041..241117abcf2 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs @@ -25,142 +25,132 @@ pub(crate) fn insert_supertraits_into_namespace( ) -> 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() { - 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; - } + handler.scope(|handler| { + 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() { + 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(handler, &supertrait.name) - .ok() - .cloned(); + let decl = ctx + .namespace + .resolve_call_path(handler, &supertrait.name) + .ok() + .cloned(); - match (decl.clone(), supertraits_of) { - // a trait can be a supertrait of either a trait or a an ABI - (Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })), _) => { - let mut trait_decl = decl_engine.get_trait(&decl_id); + match (decl.clone(), supertraits_of) { + // a trait can be a supertrait of either a trait or a an ABI + (Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })), _) => { + let mut trait_decl = decl_engine.get_trait(&decl_id); - // 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() { - error_emitted = Some(handler.emit_err(CompileError::Unimplemented( - "Using generic traits as supertraits is not supported yet.", - supertrait.name.span(), - ))); - continue; - } + // 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() { + handler.emit_err(CompileError::Unimplemented( + "Using generic traits as supertraits is not supported yet.", + supertrait.name.span(), + )); + continue; + } - // TODO: right now supertraits can't take type arguments - let mut type_arguments = vec![]; + // TODO: right now supertraits can't take type arguments + let mut type_arguments = vec![]; - // Monomorphize the trait declaration. - match ctx.monomorphize( - handler, - &mut trait_decl, - &mut type_arguments, - EnforceTypeArguments::Yes, - &supertrait.name.span(), - ) { - Ok(_) => {} - Err(err) => { - error_emitted = Some(err); + // Monomorphize the trait declaration. + if ctx + .monomorphize( + handler, + &mut trait_decl, + &mut type_arguments, + EnforceTypeArguments::Yes, + &supertrait.name.span(), + ) + .is_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, - type_id, - ); + // 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, + type_id, + ); - // Recurse to insert versions of interfaces and methods of the - // *super* supertraits. - match insert_supertraits_into_namespace( - handler, - ctx.by_ref(), - type_id, - &trait_decl.supertraits, - &SupertraitOf::Trait, - ) { - Ok(_) => {} - Err(err) => { - error_emitted = Some(err); + // Recurse to insert versions of interfaces and methods of the + // *super* supertraits. + if insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + type_id, + &trait_decl.supertraits, + &SupertraitOf::Trait, + ) + .is_err() + { continue; } } - } - // an ABI can only be a superABI of an ABI - ( - Some(ty::TyDecl::AbiDecl(ty::AbiDecl { decl_id, .. })), - SupertraitOf::Abi(subabi_span), - ) => { - let abi_decl = decl_engine.get_abi(&decl_id); - // Insert the interface surface and methods from this ABI into - // the namespace. - 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); + // an ABI can only be a superABI of an ABI + ( + Some(ty::TyDecl::AbiDecl(ty::AbiDecl { decl_id, .. })), + SupertraitOf::Abi(subabi_span), + ) => { + let abi_decl = decl_engine.get_abi(&decl_id); + // Insert the interface surface and methods from this ABI into + // the namespace. + if abi_decl + .insert_interface_surface_and_items_into_namespace( + handler, + decl_id, + ctx.by_ref(), + type_id, + Some(subabi_span.clone()), + ) + .is_err() + { continue; } - } - // Recurse to insert versions of interfaces and methods of the - // *super* superABIs. + // Recurse to insert versions of interfaces and methods of the + // *super* superABIs. - 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); + if insert_supertraits_into_namespace( + handler, + ctx.by_ref(), + type_id, + &abi_decl.supertraits, + &SupertraitOf::Abi(subabi_span.clone()), + ) + .is_err() + { continue; } } - } - // an ABI cannot be a supertrait of a trait - (Some(ty::TyDecl::AbiDecl { .. }), SupertraitOf::Trait) => { - 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(), - })) + // an ABI cannot be a supertrait of a trait + (Some(ty::TyDecl::AbiDecl { .. }), SupertraitOf::Trait) => { + handler.emit_err(CompileError::AbiAsSupertrait { + span: supertrait.name.span().clone(), + }); + } + _ => { + handler.emit_err(CompileError::TraitNotFound { + name: supertrait.name.to_string(), + span: supertrait.name.span(), + }); + } } } - } - if let Some(err) = error_emitted { - Err(err) - } else { Ok(()) - } + }) } 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 c445151b131..acac35c386b 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 @@ -59,7 +59,7 @@ impl ty::TyTraitFn { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); let trait_fn = ty::TyTraitFn { name, 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 6aa45cfc68f..0a281aacb6e 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 @@ -191,8 +191,8 @@ fn type_check_size_of_type( let targ = type_arguments[0].clone(); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); let type_id = ctx .resolve_type_with_self( @@ -202,7 +202,7 @@ fn type_check_size_of_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -243,8 +243,8 @@ fn type_check_is_reference_type( let targ = type_arguments[0].clone(); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); let type_id = ctx .resolve_type_with_self( @@ -254,7 +254,7 @@ fn type_check_is_reference_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -312,8 +312,8 @@ fn type_check_cmp( // Check for supported argument types let arg_ty = type_engine .to_typeinfo(lhs.return_type, &lhs.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .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)); @@ -384,8 +384,8 @@ fn type_check_gtf( let targ = type_arguments[0].clone(); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); let type_id = ctx .resolve_type_with_self( @@ -395,7 +395,7 @@ fn type_check_gtf( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); Ok(( ty::TyIntrinsicFunctionKind { @@ -439,8 +439,8 @@ fn type_check_addr_of( 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); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); if copy_type_info.is_copy_type() { return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), @@ -488,8 +488,8 @@ fn type_check_state_clear( 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); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, ctx.engines()) { return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), @@ -542,8 +542,8 @@ fn type_check_state_load_word( 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); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, engines) { return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), @@ -597,8 +597,8 @@ fn type_check_state_store_word( 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); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, ctx.engines()) { return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), @@ -615,8 +615,8 @@ fn type_check_state_store_word( let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); let type_id = ctx .resolve_type_with_self( @@ -626,7 +626,7 @@ fn type_check_state_store_word( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); TypeArgument { type_id, initial_type_id, @@ -686,8 +686,8 @@ fn type_check_state_quad( 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); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); if !key_ty.eq(&TypeInfo::B256, ctx.engines()) { return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), @@ -706,8 +706,8 @@ fn type_check_state_quad( let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); let type_id = ctx .resolve_type_with_self( @@ -717,7 +717,7 @@ fn type_check_state_quad( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); TypeArgument { type_id, initial_type_id, @@ -991,8 +991,8 @@ fn type_check_ptr_ops( let targ = type_arguments[0].clone(); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); let type_id = ctx .resolve_type_with_self( @@ -1002,7 +1002,7 @@ fn type_check_ptr_ops( EnforceTypeArguments::No, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); let mut ctx = ctx .by_ref() @@ -1014,8 +1014,8 @@ fn type_check_ptr_ops( // Check for supported argument types let lhs_ty = type_engine .to_typeinfo(lhs.return_type, &lhs.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); if !matches!(lhs_ty, TypeInfo::RawUntypedPtr) { return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), @@ -1088,8 +1088,8 @@ fn type_check_smo( .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) - .map_err(CompileError::from) - .unwrap_or_else(|_| TypeInfo::ErrorRecovery); + .map_err(|e| handler.emit_err(e.into())) + .unwrap_or_else(TypeInfo::ErrorRecovery); let initial_type_id = type_engine.insert(engines, initial_type_info); let type_id = ctx .resolve_type_with_self( @@ -1099,7 +1099,7 @@ fn type_check_smo( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); TypeArgument { type_id, initial_type_id, 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 c6cc5d6b829..4179174bfa0 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 @@ -124,17 +124,10 @@ pub(crate) fn matcher( let engines = ctx.engines(); // unify the type of the scrutinee with the type of the expression - 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); - } + handler.scope(|h| { + type_engine.unify(h, engines, type_id, exp.return_type, &span, "", None); + Ok(()) + })?; match variant { ty::TyScrutineeVariant::Or(elems) => { 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 8669df1e19a..63a08656e1a 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 @@ -69,14 +69,7 @@ impl ty::TyMatchBranch { // unify the return type from the typed result with the type annotation if !typed_result.deterministically_aborts(decl_engine, true) { - 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); - } + ctx.unify_with_self(handler, typed_result.return_type, &typed_result.span); } // if the typed branch result is a code block, then add the contents 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 56f322207dd..c8960606155 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 @@ -26,23 +26,22 @@ impl ty::TyMatchExpression { 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) = - match ty::TyMatchBranch::type_check(handler, ctx.by_ref(), &typed_value, branch) { + handler.scope(|handler| { + for branch in branches.into_iter() { + 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; - } + Err(_) => continue, }; - typed_branches.push(typed_branch); - typed_scrutinees.push(typed_scrutinee); - } - - if let Some(err) = error_emitted { - return Err(err); - } + typed_branches.push(typed_branch); + typed_scrutinees.push(typed_scrutinee); + } + Ok(()) + })?; let typed_exp = ty::TyMatchExpression { value_type_id: typed_value.return_type, 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 2cdb02c1472..e7cec69aa0c 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 @@ -101,7 +101,7 @@ impl ty::TyScrutinee { } } Scrutinee::Tuple { elems, span } => type_check_tuple(handler, ctx, elems, span), - Scrutinee::Error { .. } => Err(ErrorEmitted), + Scrutinee::Error { err, .. } => Err(err), } } } 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 7a83f703851..629d598345b 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 @@ -113,7 +113,7 @@ impl ty::TyExpression { 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)), + ExpressionKind::Error(_, err) => Ok(ty::TyExpression::error(err, span, engines)), ExpressionKind::Literal(lit) => Ok(Self::type_check_literal(engines, lit, span)), ExpressionKind::AmbiguousVariableExpression(name) => { let call_path = CallPath { @@ -349,7 +349,7 @@ impl ty::TyExpression { ); let expr_span = expr.span(); let expr = ty::TyExpression::type_check(handler, ctx, *expr) - .unwrap_or_else(|_| ty::TyExpression::error(expr_span, engines)); + .unwrap_or_else(|err| ty::TyExpression::error(err, expr_span, engines)); let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Return(Box::new(expr)), return_type: type_engine.insert(engines, TypeInfo::Unknown), @@ -365,13 +365,7 @@ impl ty::TyExpression { }; // if the return type cannot be cast into the annotation type then it is a type error - 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); - } + ctx.unify_with_self(handler, typed_expression.return_type, &expr_span); // The annotation may result in a cast, which is handled in the type engine. typed_expression.return_type = ctx @@ -382,7 +376,7 @@ impl ty::TyExpression { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); // Literals of type Numeric can now be resolved if typed_expression.return_type is // an UnsignedInteger or a Numeric @@ -483,19 +477,19 @@ impl ty::TyExpression { } } Some(a) => { - handler.emit_err(CompileError::NotAVariable { + let err = handler.emit_err(CompileError::NotAVariable { name: name.clone(), what_it_is: a.friendly_type_name(), span, }); - ty::TyExpression::error(name.span(), engines) + ty::TyExpression::error(err, name.span(), engines) } None => { - handler.emit_err(CompileError::UnknownVariable { + let err = handler.emit_err(CompileError::UnknownVariable { var_name: name.clone(), span, }); - ty::TyExpression::error(name.span(), engines) + ty::TyExpression::error(err, name.span(), engines) } }; Ok(exp) @@ -533,10 +527,10 @@ impl ty::TyExpression { let mut ctx = ctx.with_help_text(""); let engines = ctx.engines(); let typed_lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(lhs.span(), engines)); + .unwrap_or_else(|err| ty::TyExpression::error(err, lhs.span(), engines)); let typed_rhs = ty::TyExpression::type_check(handler, ctx.by_ref(), rhs.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(rhs.span(), engines)); + .unwrap_or_else(|err| ty::TyExpression::error(err, rhs.span(), engines)); let type_annotation = ctx.type_annotation(); let exp = instantiate_lazy_operator(op, typed_lhs, typed_rhs, type_annotation, span); @@ -560,13 +554,7 @@ impl ty::TyExpression { ) }); - 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); - } + ctx.unify_with_self(handler, block_return_type, &span); let exp = ty::TyExpression { expression: ty::TyExpressionVariant::CodeBlock(ty::TyCodeBlock { @@ -596,7 +584,7 @@ impl ty::TyExpression { .with_help_text("The condition of an if expression must be a boolean expression.") .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean)); ty::TyExpression::type_check(handler, ctx, condition.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(condition.span(), engines)) + .unwrap_or_else(|err| ty::TyExpression::error(err, condition.span(), engines)) }; let then = { let ctx = ctx @@ -604,7 +592,7 @@ impl ty::TyExpression { .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); ty::TyExpression::type_check(handler, ctx, then.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(then.span(), engines)) + .unwrap_or_else(|err| ty::TyExpression::error(err, then.span(), engines)) }; let r#else = r#else.map(|expr| { let ctx = ctx @@ -612,7 +600,7 @@ impl ty::TyExpression { .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); ty::TyExpression::type_check(handler, ctx, expr.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(expr.span(), engines)) + .unwrap_or_else(|err| ty::TyExpression::error(err, expr.span(), engines)) }); let exp = instantiate_if_expression(handler, ctx, condition, then, r#else, span)?; Ok(exp) @@ -635,7 +623,7 @@ impl ty::TyExpression { .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); ty::TyExpression::type_check(handler, ctx, value.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(value.span(), engines)) + .unwrap_or_else(|err| ty::TyExpression::error(err, value.span(), engines)) }; let type_id = typed_value.return_type; @@ -719,7 +707,7 @@ impl ty::TyExpression { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); // type check the initializers let typed_registers = @@ -735,8 +723,8 @@ impl ty::TyExpression { ); ty::TyExpression::type_check(handler, ctx, initializer.clone()) - .unwrap_or_else(|_| { - ty::TyExpression::error(initializer.span(), engines) + .unwrap_or_else(|err| { + ty::TyExpression::error(err, initializer.span(), engines) }) }), }, @@ -810,7 +798,7 @@ impl ty::TyExpression { .with_help_text("tuple field type does not match the expected type") .with_type_annotation(field_type.type_id); let typed_field = ty::TyExpression::type_check(handler, ctx, field) - .unwrap_or_else(|_| ty::TyExpression::error(field_span, engines)); + .unwrap_or_else(|err| ty::TyExpression::error(err, field_span, engines)); typed_field_types.push(TypeArgument { type_id: typed_field.return_type, initial_type_id: field_type.type_id, @@ -1310,8 +1298,8 @@ impl ty::TyExpression { ctx.self_type(), ctx.engines(), ) { - Ok(val) => val, - Err(_) => return None, + Ok(Some(val)) => val, + Ok(None) | Err(_) => return None, }; Some((const_decl_ref, call_path_binding.clone())) @@ -1338,7 +1326,7 @@ impl ty::TyExpression { .with_help_text("An address that is being ABI cast must be of type b256") .with_type_annotation(type_engine.insert(engines, TypeInfo::B256)); ty::TyExpression::type_check(handler, ctx, address) - .unwrap_or_else(|_| ty::TyExpression::error(err_span, engines)) + .unwrap_or_else(|err| ty::TyExpression::error(err, err_span, engines)) }; // look up the call path and get the declaration it references @@ -1513,16 +1501,17 @@ impl ty::TyExpression { .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); Self::type_check(handler, ctx, expr) - .unwrap_or_else(|_| ty::TyExpression::error(span, engines)) + .unwrap_or_else(|err| ty::TyExpression::error(err, span, engines)) }) .collect(); let elem_type = typed_contents[0].return_type; for typed_elem in &typed_contents[1..] { - let (new_warnings, new_errors) = ctx - .by_ref() + let h = Handler::default(); + ctx.by_ref() .with_type_annotation(elem_type) - .unify_with_self(typed_elem.return_type, &typed_elem.span); + .unify_with_self(&h, typed_elem.return_type, &typed_elem.span); + let (new_errors, new_warnings) = h.consume(); let no_warnings = new_warnings.is_empty(); let no_errors = new_errors.is_empty(); for warn in new_warnings { @@ -1744,8 +1733,8 @@ impl ty::TyExpression { let ctx = ctx.by_ref().with_help_text(""); let typed_index = ty::TyExpression::type_check(handler, ctx, index.as_ref().clone()) - .unwrap_or_else(|_| { - ty::TyExpression::error(span.clone(), engines) + .unwrap_or_else(|err| { + ty::TyExpression::error(err, span.clone(), engines) }); names_vec.push(ty::ProjectionKind::ArrayIndex { index: Box::new(typed_index), @@ -1771,7 +1760,7 @@ impl ty::TyExpression { let ctx = ctx.with_type_annotation(ty_of_field).with_help_text(""); let rhs_span = rhs.span(); let rhs = ty::TyExpression::type_check(handler, ctx, rhs) - .unwrap_or_else(|_| ty::TyExpression::error(rhs_span, engines)); + .unwrap_or_else(|err| ty::TyExpression::error(err, rhs_span, engines)); Ok(ty::TyExpression { expression: ty::TyExpressionVariant::Reassignment(Box::new( @@ -1881,8 +1870,8 @@ impl ty::TyExpression { Ok(exp) } Err(e) => { - handler.emit_err(e); - let exp = ty::TyExpression::error(span, engines); + let err = handler.emit_err(e); + let exp = ty::TyExpression::error(err, span, engines); Ok(exp) } } 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 61902a7b5e2..2a9e0e5553b 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 @@ -77,24 +77,18 @@ pub(crate) fn instantiate_enum( let typed_expr = ty::TyExpression::type_check(handler, enum_ctx, single_expr.clone())?; // unify the value of the argument with the variant - 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); - } + handler.scope(|handler| { + type_engine.unify( + handler, + engines, + typed_expr.return_type, + enum_variant.type_argument.type_id, + span, + "Enum instantiator must match its declared variant type.", + None, + ); + Ok(()) + })?; // we now know that the instantiator type matches the declared type, via the above tpe // check 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 f9db8859f90..633cd386786 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 @@ -103,27 +103,21 @@ fn type_check_arguments( let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let mut error_emitted = None; - - let typed_arguments = arguments - .into_iter() - .map(|arg| { - let ctx = ctx - .by_ref() - .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); - ty::TyExpression::type_check(handler, ctx, arg.clone()).unwrap_or_else(|err| { - error_emitted = Some(err); - ty::TyExpression::error(arg.span(), engines) + handler.scope(|handler| { + let typed_arguments = arguments + .into_iter() + .map(|arg| { + let ctx = ctx + .by_ref() + .with_help_text("") + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); + ty::TyExpression::type_check(handler, ctx, arg.clone()) + .unwrap_or_else(|err| ty::TyExpression::error(err, arg.span(), engines)) }) - }) - .collect(); + .collect(); - if let Some(err) = error_emitted { - Err(err) - } else { Ok(typed_arguments) - } + }) } /// Unifies the types of the arguments with the types of the parameters. Returns @@ -138,50 +132,42 @@ fn unify_arguments_and_parameters( 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 - - 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 \ + handler.scope(|handler| { + for (arg, param) in typed_arguments.into_iter().zip(parameters.iter()) { + // unify the type of the argument with the type of the param + + let unify_res = handler.scope(|unify_handler| { + type_engine.unify( + unify_handler, + 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, - ); - 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() { - error_emitted = Some(handler.emit_err( - CompileError::ImmutableArgumentToMutableParameter { + None, + ); + Ok(()) + }); + if unify_res.is_err() { + 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() { + handler.emit_err(CompileError::ImmutableArgumentToMutableParameter { span: arg.span.clone(), - }, - )); - } + }); + } - typed_arguments_and_names.push((param.name.clone(), arg)); - } + typed_arguments_and_names.push((param.name.clone(), arg)); + } - if let Some(err) = error_emitted { - Err(err) - } else { Ok(typed_arguments_and_names) - } + }) } pub(crate) fn check_function_arguments_arity( 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 a6ddc826a5b..9864a4bf053 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 @@ -30,7 +30,8 @@ pub(crate) fn instantiate_if_expression( } else { type_engine.insert(engines, TypeInfo::Tuple(vec![])) }; - let (warnings, errors) = type_engine.unify_with_self( + type_engine.unify_with_self( + handler, engines, then.return_type, ty_to_check, @@ -39,12 +40,6 @@ pub(crate) fn instantiate_if_expression( "`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| { @@ -56,7 +51,8 @@ pub(crate) fn instantiate_if_expression( }; if !else_deterministically_aborts { // if this does not deterministically_abort, check the block return type - let (warnings, errors) = type_engine.unify_with_self( + type_engine.unify_with_self( + handler, engines, r#else.return_type, ty_to_check, @@ -65,12 +61,6 @@ pub(crate) fn instantiate_if_expression( "`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) }); @@ -81,7 +71,10 @@ 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 (new_warnings, new_errors) = type_engine.unify_with_self( + // delay emitting the errors until we decide if this is a missing else branch or some other set of errors + let h = Handler::default(); + type_engine.unify_with_self( + &h, engines, then.return_type, r#else_ret_ty, @@ -90,6 +83,8 @@ pub(crate) fn instantiate_if_expression( "The two branches of an if expression must return the same type.", None, ); + + let (new_errors, new_warnings) = h.consume(); for warn in new_warnings { handler.emit_warn(warn); } 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 9de45a3f5ba..bf6f8f2f8bf 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 @@ -36,7 +36,7 @@ pub(crate) fn type_check_method_application( .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)); args_buf.push_back( ty::TyExpression::type_check(handler, ctx, arg.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(span.clone(), engines)), + .unwrap_or_else(|err| ty::TyExpression::error(err, span.clone(), engines)), ); } @@ -115,8 +115,9 @@ pub(crate) fn type_check_method_application( .with_type_annotation(type_annotation); contract_call_params_map.insert( param.name.to_string(), - ty::TyExpression::type_check(handler, ctx, param.value) - .unwrap_or_else(|_| ty::TyExpression::error(span.clone(), engines)), + ty::TyExpression::type_check(handler, ctx, param.value).unwrap_or_else( + |err| ty::TyExpression::error(err, span.clone(), engines), + ), ); } _ => { @@ -370,40 +371,34 @@ fn unify_arguments_and_parameters( 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 - 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)); - } + handler.scope(|handler| { + for (arg, param) in arguments.into_iter().zip(parameters.iter()) { + // unify the type of the argument with the type of the param + let unify_res = handler.scope(|handler| { + type_engine.unify_with_self( + handler, + 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(), + }), + ); + Ok(()) + }); + if unify_res.is_err() { + continue; + } - if let Some(err) = error_emitted { - Err(err) - } else { + typed_arguments_and_names.push((param.name.clone(), arg)); + } Ok(typed_arguments_and_names) - } + }) } pub(crate) fn resolve_method_name( @@ -425,7 +420,7 @@ pub(crate) fn resolve_method_name( // type check the call path let type_id = call_path_binding .type_check_with_type_info(handler, &mut ctx) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); // find the module that the symbol is in let type_info_prefix = ctx 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 fb111b76d4e..2a43e12f4e7 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 @@ -79,7 +79,7 @@ pub(crate) fn struct_instantiation( EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); // extract the struct name and fields from the type info let type_info = type_engine.get(type_id); @@ -159,7 +159,7 @@ fn type_check_field_arguments( struct_field.span = field.value.span.clone(); } None => { - handler.emit_err(CompileError::StructMissingField { + let err = handler.emit_err(CompileError::StructMissingField { field_name: struct_field.name.clone(), struct_name: struct_name.clone(), span: span.clone(), @@ -168,7 +168,7 @@ fn type_check_field_arguments( name: struct_field.name.clone(), value: ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery), + return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery(err)), span: span.clone(), }, }); @@ -190,30 +190,20 @@ fn unify_field_arguments_and_struct_fields( 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) { - 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)); + handler.scope(|handler| { + for struct_field in struct_fields.iter() { + if let Some(typed_field) = typed_fields.iter().find(|x| x.name == struct_field.name) { + type_engine.unify( + handler, + 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, + ); } } - } - - if let Some(err) = error_emitted { - Err(err) - } else { Ok(()) - } + }) } diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index a469cece311..209a1d6fc8c 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -146,14 +146,14 @@ impl ty::TyAstNode { .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown)) .with_help_text(""); let inner = ty::TyExpression::type_check(handler, ctx, expr.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(expr.span(), engines)); + .unwrap_or_else(|err| ty::TyExpression::error(err, 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 = ty::TyExpression::type_check(handler, ctx, expr.clone()) - .unwrap_or_else(|_| ty::TyExpression::error(expr.span(), engines)); + .unwrap_or_else(|err| ty::TyExpression::error(err, expr.span(), engines)); ty::TyAstNodeContent::ImplicitReturnExpression(typed_expr) } }, diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 7995a90c54b..01ce2861229 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -190,9 +190,8 @@ impl Namespace { // If the type that we are looking for is the error recovery type, then // we want to return the error case without creating a new error // message. - if let TypeInfo::ErrorRecovery = type_engine.get(type_id) { - // FIXME: find a better way to handle error recovery - return Err(ErrorEmitted); + if let TypeInfo::ErrorRecovery(err) = type_engine.get(type_id) { + return Err(err); } // grab the local module @@ -215,7 +214,7 @@ impl Namespace { self, item_prefix, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); // grab the module where the type itself is declared let type_module = self.root().check_submodule(handler, item_prefix)?; @@ -452,11 +451,11 @@ impl Namespace { return Ok(method_decl_ref); } - if !args_buf - .get(0) - .map(|x| type_engine.get(x.return_type)) - .eq(&Some(TypeInfo::ErrorRecovery), engines) + if let Some(TypeInfo::ErrorRecovery(err)) = + args_buf.get(0).map(|x| type_engine.get(x.return_type)) { + Err(err) + } else { if try_inserting_trait_impl_on_failure { // Retrieve the implemented traits for the type and insert them in the namespace. // insert_trait_implementation_for_type is already called when we do type check of structs, enums, arrays and tuples. @@ -482,13 +481,12 @@ impl Namespace { } else { engines.help_out(type_id).to_string() }; - handler.emit_err(CompileError::MethodNotFound { + Err(handler.emit_err(CompileError::MethodNotFound { method_name: method_name.clone(), type_name, span: method_name.span(), - }); + })) } - Err(ErrorEmitted) } /// Given a name and a type (plus a `self_type` to potentially @@ -505,7 +503,7 @@ impl Namespace { item_name: &Ident, self_type: TypeId, engines: &Engines, - ) -> Result { + ) -> Result, ErrorEmitted> { let matching_item_decl_refs = self.find_items_for_type( handler, type_id, @@ -523,11 +521,7 @@ impl Namespace { }) .collect::>(); - if let Some(constant_decl_ref) = matching_constant_decl_refs.first() { - Ok(constant_decl_ref.clone()) - } else { - Err(ErrorEmitted) - } + Ok(matching_constant_decl_refs.first().cloned()) } /// Short-hand for performing a [Module::star_import] with `mod_path` as the destination. diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 4a67366fb0f..608d5376848 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -123,161 +123,152 @@ impl TraitMap { 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 { - TyImplItem::Fn(decl_ref) => { - if trait_items - .insert(decl_ref.name().clone().to_string(), item.clone()) - .is_some() - { - // duplicate method name - error_emitted = - Some(handler.emit_err(CompileError::MultipleDefinitionsOfName { + handler.scope(|handler| { + let mut trait_items: TraitItems = im::HashMap::new(); + for item in items.iter() { + match item { + TyImplItem::Fn(decl_ref) => { + if trait_items + .insert(decl_ref.name().clone().to_string(), item.clone()) + .is_some() + { + // duplicate method name + handler.emit_err(CompileError::MultipleDefinitionsOfName { name: decl_ref.name().clone(), span: decl_ref.span(), - })); + }); + } + } + TyImplItem::Constant(decl_ref) => { + trait_items.insert(decl_ref.name().to_string(), item.clone()); } - } - TyImplItem::Constant(decl_ref) => { - trait_items.insert(decl_ref.name().to_string(), item.clone()); } } - } - // check to see if adding this trait will produce a conflicting definition - let trait_type_id = type_engine.insert( - engines, - TypeInfo::Custom { - call_path: trait_name.suffix.clone().into(), - type_arguments: if trait_type_args.is_empty() { - None - } else { - Some(trait_type_args.clone()) - }, - }, - ); - for TraitEntry { - key: - TraitKey { - name: map_trait_name, - type_id: map_type_id, - trait_decl_span: _, - }, - value: - TraitValue { - trait_items: map_trait_items, - .. - }, - } in self.trait_impls.iter() - { - let CallPath { - suffix: - TraitSuffix { - name: map_trait_name_suffix, - args: map_trait_type_args, - }, - .. - } = map_trait_name; - let map_trait_type_id = type_engine.insert( + // check to see if adding this trait will produce a conflicting definition + let trait_type_id = type_engine.insert( engines, TypeInfo::Custom { - call_path: map_trait_name_suffix.clone().into(), - type_arguments: if map_trait_type_args.is_empty() { + call_path: trait_name.suffix.clone().into(), + type_arguments: if trait_type_args.is_empty() { None } else { - Some(map_trait_type_args.to_vec()) + Some(trait_type_args.clone()) }, }, ); + for TraitEntry { + key: + TraitKey { + name: map_trait_name, + type_id: map_type_id, + trait_decl_span: _, + }, + value: + TraitValue { + trait_items: map_trait_items, + .. + }, + } in self.trait_impls.iter() + { + let CallPath { + suffix: + TraitSuffix { + name: map_trait_name_suffix, + args: map_trait_type_args, + }, + .. + } = map_trait_name; + let map_trait_type_id = type_engine.insert( + engines, + TypeInfo::Custom { + call_path: map_trait_name_suffix.clone().into(), + type_arguments: if map_trait_type_args.is_empty() { + None + } else { + Some(map_trait_type_args.to_vec()) + }, + }, + ); - let unify_checker = UnifyCheck::constraint_subset(engines); - let types_are_subset = unify_checker.check(type_id, *map_type_id); - let traits_are_subset = unify_checker.check(trait_type_id, map_trait_type_id); + let unify_checker = UnifyCheck::constraint_subset(engines); + let types_are_subset = unify_checker.check(type_id, *map_type_id); + let traits_are_subset = unify_checker.check(trait_type_id, map_trait_type_id); - if types_are_subset && traits_are_subset && !is_impl_self { - let trait_name_str = format!( - "{}{}", - trait_name.suffix, - if trait_type_args.is_empty() { - String::new() - } else { - format!( - "<{}>", - trait_type_args - .iter() - .map(|type_arg| engines.help_out(type_arg).to_string()) - .collect::>() - .join(", ") - ) - } - ); - error_emitted = Some(handler.emit_err( - CompileError::ConflictingImplsForTraitAndType { + if types_are_subset && traits_are_subset && !is_impl_self { + let trait_name_str = format!( + "{}{}", + trait_name.suffix, + if trait_type_args.is_empty() { + String::new() + } else { + format!( + "<{}>", + trait_type_args + .iter() + .map(|type_arg| engines.help_out(type_arg).to_string()) + .collect::>() + .join(", ") + ) + } + ); + 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() { - error_emitted = Some(handler.emit_err( - CompileError::DuplicateDeclDefinedForType { + }); + } 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() { + 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(), + 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() { - error_emitted = Some(handler.emit_err( - CompileError::DuplicateDeclDefinedForType { + ty::TyTraitItem::Constant(decl_ref) => { + if map_trait_items.get(name).is_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(), + type_implementing_for: engines + .help_out(type_id) + .to_string(), span: decl_ref.name().span(), - }, - )); + }); + } } } } } } - } - let trait_name: TraitName = CallPath { - prefixes: trait_name.prefixes, - suffix: TraitSuffix { - name: trait_name.suffix, - args: trait_type_args, - }, - is_absolute: trait_name.is_absolute, - }; + let trait_name: TraitName = CallPath { + prefixes: trait_name.prefixes, + suffix: TraitSuffix { + name: trait_name.suffix, + args: trait_type_args, + }, + is_absolute: trait_name.is_absolute, + }; - // even if there is a conflicting definition, add the trait anyway - self.insert_inner( - trait_name, - impl_span.clone(), - trait_decl_span, - type_id, - trait_items, - engines, - ); + // even if there is a conflicting definition, add the trait anyway + self.insert_inner( + trait_name, + impl_span.clone(), + trait_decl_span, + type_id, + trait_items, + engines, + ); - if let Some(err) = error_emitted { - Err(err) - } else { Ok(()) - } + }) } fn insert_inner( @@ -736,10 +727,7 @@ impl TraitMap { let mut items = vec![]; // small performance gain in bad case - if type_engine - .get(type_id) - .eq(&TypeInfo::ErrorRecovery, engines) - { + if matches!(type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) { return items; } for entry in self.trait_impls.iter() { @@ -771,10 +759,7 @@ impl TraitMap { let mut spans = vec![]; // small performance gain in bad case - if type_engine - .get(*type_id) - .eq(&TypeInfo::ErrorRecovery, engines) - { + if matches!(type_engine.get(*type_id), TypeInfo::ErrorRecovery(_)) { return spans; } for entry in self.trait_impls.iter() { @@ -824,10 +809,7 @@ impl TraitMap { let unify_check = UnifyCheck::non_dynamic_equality(engines); let mut items = vec![]; // small performance gain in bad case - if type_engine - .get(type_id) - .eq(&TypeInfo::ErrorRecovery, engines) - { + if matches!(type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) { return items; } for e in self.trait_impls.iter() { @@ -853,10 +835,7 @@ impl TraitMap { let unify_check = UnifyCheck::non_dynamic_equality(engines); let mut trait_names = vec![]; // small performance gain in bad case - if type_engine - .get(type_id) - .eq(&TypeInfo::ErrorRecovery, engines) - { + if matches!(type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) { return trait_names; } for entry in self.trait_impls.iter() { @@ -951,20 +930,16 @@ 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 - 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 let Some(err) = error_emitted { - Err(err) - } else { + handler.scope(|handler| { + for trait_name in required_traits_names.difference(&relevant_impld_traits_names) { + // TODO: use a better span + handler.emit_err(CompileError::TraitConstraintNotSatisfied { + ty: engines.help_out(type_id).to_string(), + trait_name: trait_name.to_string(), + span: access_span.clone(), + }); + } Ok(()) - } + }) } } diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 5f718814627..ffb52274949 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -32,27 +32,26 @@ pub(crate) fn order_ast_nodes_by_dependency( // Check here for recursive calls now that we have a nice map of the dependencies to help us. let mut errors = find_recursive_decls(&decl_dependencies); - if !errors.is_empty() { + + handler.scope(|handler| { // 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()); - 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) - })) - } + for err in errors { + handler.emit_err(err); + } + Ok(()) + })?; + + // 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) + })) } // ------------------------------------------------------------------------------------------------- @@ -578,7 +577,7 @@ impl Dependencies { | ExpressionKind::Break | ExpressionKind::Continue | ExpressionKind::StorageAccess(_) - | ExpressionKind::Error(_) => self, + | ExpressionKind::Error(_, _) => self, ExpressionKind::Tuple(fields) => self.gather_from_iter(fields.iter(), |deps, field| { deps.gather_from_expr(engines, field) @@ -864,7 +863,7 @@ fn type_info_name(type_info: &TypeInfo) -> String { TypeInfo::B256 => "b256", TypeInfo::Numeric => "numeric", TypeInfo::Contract => "contract", - TypeInfo::ErrorRecovery => "err_recov", + TypeInfo::ErrorRecovery(_) => "err_recov", TypeInfo::Unknown => "unknown", TypeInfo::UnknownGeneric { name, .. } => return format!("generic {name}"), TypeInfo::TypeParam(_) => "type param", diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 4d4c88d6306..904971557bd 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -9,12 +9,8 @@ use crate::{ type_system::{ EnforceTypeArguments, MonomorphizeHelper, SubstTypes, TypeArgument, TypeId, TypeInfo, }, - CompileWarning, -}; -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, }; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{span::Span, Ident}; /// Contextual state tracked and accumulated throughout type-checking. @@ -322,12 +318,9 @@ impl<'a> TypeCheckContext<'a> { /// Short-hand around `type_system::unify_with_self`, where the `TypeCheckContext` provides the /// type annotation, self type and help text. - pub(crate) fn unify_with_self( - &self, - ty: TypeId, - span: &Span, - ) -> (Vec, Vec) { + pub(crate) fn unify_with_self(&self, handler: &Handler, ty: TypeId, span: &Span) { self.engines.te().unify_with_self( + handler, self.engines(), ty, self.type_annotation(), diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index f44747832ed..0a95f58855a 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -1626,10 +1626,10 @@ fn expr_func_app_to_expression_kind( .. } = match *func { Expr::Path(path_expr) => path_expr, - Expr::Error(_) => { + Expr::Error(_, err) => { // FIXME we can do better here and return function application expression here // if there are no parsing errors in the arguments - return Ok(ExpressionKind::Error(Box::new([span]))); + return Ok(ExpressionKind::Error(Box::new([span]), err)); } _ => { let error = ConvertParseTreeError::FunctionArbitraryExpression { span: func.span() }; @@ -1768,8 +1768,8 @@ fn expr_to_expression( ) -> Result { let span = expr.span(); let expression = match expr { - Expr::Error(part_spans) => Expression { - kind: ExpressionKind::Error(part_spans), + Expr::Error(part_spans, err) => Expression { + kind: ExpressionKind::Error(part_spans, err), span, }, Expr::Path(path_expr) => path_expr_to_expression(context, handler, engines, path_expr)?, @@ -3639,7 +3639,7 @@ fn pattern_to_scrutinee( }, span, }, - Pattern::Error(spans) => Scrutinee::Error { spans }, + Pattern::Error(spans, err) => Scrutinee::Error { spans, err }, }; Ok(scrutinee) } diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 54a3b830fb9..ddba2260ff1 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -191,7 +191,7 @@ impl TypeBinding> { EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err))); Ok(type_id) } @@ -260,7 +260,9 @@ impl TypeCheckTypeBinding for TypeBinding { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|_| type_engine.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| { + type_engine.insert(engines, TypeInfo::ErrorRecovery(err)) + }); } } } 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 ba878feebee..22b519ca48c 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -93,24 +93,17 @@ impl CollectTypesMetadata for TraitConstraint { ctx: &mut CollectTypesMetadataContext, ) -> Result, ErrorEmitted> { let mut res = vec![]; - let mut error_emitted = None; - for type_arg in self.type_arguments.iter() { - res.extend( - match type_arg.type_id.collect_types_metadata(handler, ctx) { - Ok(res) => res, - Err(err) => { - error_emitted = Some(err); - continue; - } - }, - ); - } - - if let Some(err) = error_emitted { - Err(err) - } else { + handler.scope(|handler| { + for type_arg in self.type_arguments.iter() { + res.extend( + match type_arg.type_id.collect_types_metadata(handler, ctx) { + Ok(res) => res, + Err(_) => continue, + }, + ); + } Ok(res) - } + }) } } @@ -163,10 +156,10 @@ impl TraitConstraint { &type_argument.span, None, ) - .unwrap_or_else(|_| { + .unwrap_or_else(|err| { ctx.engines .te() - .insert(ctx.engines(), TypeInfo::ErrorRecovery) + .insert(ctx.engines(), TypeInfo::ErrorRecovery(err)) }); } 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 073c91a8964..6a5791b027c 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -140,25 +140,18 @@ impl TypeParameter { ) -> 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( - match TypeParameter::type_check(handler, ctx.by_ref(), type_param) { - Ok(res) => res, - Err(err) => { - error_emitted = Some(err); - continue; - } - }, - ) - } + handler.scope(|handler| { + for type_param in type_params.into_iter() { + new_type_params.push( + match TypeParameter::type_check(handler, ctx.by_ref(), type_param) { + Ok(res) => res, + Err(_) => continue, + }, + ) + } - if let Some(err) = error_emitted { - Err(err) - } else { Ok(new_type_params) - } + }) } /// Type checks a [TypeParameter] (including its [TraitConstraint]s) and @@ -214,7 +207,8 @@ impl TypeParameter { type_id: sy_type_id, .. }) => { - let (warnings, errors) = ctx.engines().te().unify( + ctx.engines().te().unify( + handler, ctx.engines(), type_id, *sy_type_id, @@ -222,12 +216,6 @@ impl TypeParameter { "", None, ); - for warn in warnings { - handler.emit_warn(warn); - } - for err in errors { - handler.emit_err(err); - } } _ => { handler.emit_err(CompileError::Internal( @@ -271,69 +259,59 @@ impl TypeParameter { 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, - trait_constraints, - .. - } = type_param; - - // Check to see if the trait constraints are satisfied. - match ctx - .namespace - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - handler, - *type_id, + handler.scope(|handler| { + for type_param in type_parameters.iter() { + let TypeParameter { + 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 { - trait_name, - type_arguments: trait_type_arguments, - } = trait_constraint; - - let (trait_interface_item_refs, trait_item_refs, trait_impld_item_refs) = - match handle_trait( + .. + } = type_param; + + // Check to see if the trait constraints are satisfied. + match ctx + .namespace + .implemented_traits + .check_if_trait_constraints_are_satisfied_for_type( handler, - ctx.by_ref(), *type_id, - trait_name, - trait_type_arguments, + trait_constraints, + access_span, + ctx.engines(), ) { - 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); + Ok(res) => res, + Err(_) => continue, + } + + for trait_constraint in trait_constraints.iter() { + let TraitConstraint { + trait_name, + type_arguments: trait_type_arguments, + } = trait_constraint; + + 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(_) => continue, + }; + interface_item_refs.extend(trait_interface_item_refs); + item_refs.extend(trait_item_refs); + impld_item_refs.extend(trait_impld_item_refs); + } } - } - 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) - } + }) } } @@ -350,56 +328,49 @@ fn handle_trait( let mut item_refs: ItemMap = BTreeMap::new(); let mut impld_item_refs: ItemMap = BTreeMap::new(); - let mut error_emitted = None; + handler.scope(|handler| { + match ctx + .namespace + .resolve_call_path(handler, trait_name) + .ok() + .cloned() + { + Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { + let trait_decl = decl_engine.get_trait(&decl_id); - match ctx - .namespace - .resolve_call_path(handler, trait_name) - .ok() - .cloned() - { - Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { - let trait_decl = decl_engine.get_trait(&decl_id); + let (trait_interface_item_refs, trait_item_refs, trait_impld_item_refs) = + trait_decl.retrieve_interface_surface_and_items_and_implemented_items_for_type( + ctx.by_ref(), + type_id, + trait_name, + type_arguments, + ); + interface_item_refs.extend(trait_interface_item_refs); + item_refs.extend(trait_item_refs); + impld_item_refs.extend(trait_impld_item_refs); - let (trait_interface_item_refs, trait_item_refs, trait_impld_item_refs) = trait_decl - .retrieve_interface_surface_and_items_and_implemented_items_for_type( - ctx.by_ref(), - type_id, - trait_name, - type_arguments, - ); - interface_item_refs.extend(trait_interface_item_refs); - item_refs.extend(trait_item_refs); - impld_item_refs.extend(trait_impld_item_refs); - - for supertrait in trait_decl.supertraits.iter() { - let ( - supertrait_interface_item_refs, - supertrait_item_refs, - supertrait_impld_item_refs, - ) = 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); + for supertrait in trait_decl.supertraits.iter() { + let ( + supertrait_interface_item_refs, + supertrait_item_refs, + supertrait_impld_item_refs, + ) = match handle_trait(handler, ctx.by_ref(), type_id, &supertrait.name, &[]) { + Ok(res) => res, + Err(_) => continue, + }; + interface_item_refs.extend(supertrait_interface_item_refs); + item_refs.extend(supertrait_item_refs); + impld_item_refs.extend(supertrait_impld_item_refs); + } + } + _ => { + handler.emit_err(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 let Some(err) = error_emitted { - Err(err) - } else { 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 528ac3fd8f3..3be8eefb432 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -11,7 +11,7 @@ use crate::{ namespace::Path, type_system::priv_prelude::*, Namespace, }; -use sway_error::{error::CompileError, type_error::TypeError, warning::CompileWarning}; +use sway_error::{error::CompileError, type_error::TypeError}; use sway_types::{span::Span, Ident, Spanned}; #[derive(Debug, Default)] @@ -161,7 +161,7 @@ impl TypeEngine { namespace, mod_path, ) - .unwrap_or_else(|_| self.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| self.insert(engines, TypeInfo::ErrorRecovery(err))); } let type_mapping = TypeSubstMap::from_type_parameters_and_type_arguments( value @@ -186,6 +186,7 @@ impl TypeEngine { #[allow(clippy::too_many_arguments)] pub(crate) fn unify_with_self( &self, + handler: &Handler, engines: &Engines, mut received: TypeId, mut expected: TypeId, @@ -193,10 +194,18 @@ impl TypeEngine { span: &Span, help_text: &str, err_override: Option, - ) -> (Vec, Vec) { + ) { received.replace_self_type(engines, self_type); expected.replace_self_type(engines, self_type); - self.unify(engines, received, expected, span, help_text, err_override) + self.unify( + handler, + engines, + received, + expected, + span, + help_text, + err_override, + ) } /// Make the types of `received` and `expected` equivalent (or produce an @@ -206,25 +215,26 @@ impl TypeEngine { /// `expected`, except in cases where `received` has more type information /// than `expected` (e.g. when `expected` is a generic type and `received` /// is not). + #[allow(clippy::too_many_arguments)] pub(crate) fn unify( &self, + handler: &Handler, engines: &Engines, received: TypeId, expected: TypeId, span: &Span, help_text: &str, err_override: Option, - ) -> (Vec, Vec) { + ) { if !UnifyCheck::coercion(engines).check(received, expected) { // create a "mismatched type" error unless the `err_override` // argument has been provided - let mut errors = vec![]; match err_override { Some(err_override) => { - errors.push(err_override); + handler.emit_err(err_override); } None => { - errors.push(CompileError::TypeError(TypeError::MismatchedType { + handler.emit_err(CompileError::TypeError(TypeError::MismatchedType { expected: engines.help_out(expected).to_string(), received: engines.help_out(received).to_string(), help_text: help_text.to_string(), @@ -232,18 +242,17 @@ impl TypeEngine { })); } } - return (vec![], errors); + return; } - let (warnings, errors) = - normalize_err(Unifier::new(engines, help_text).unify(received, expected, span)); - if errors.is_empty() { - (warnings, errors) - } else if err_override.is_some() { - // return the errors from unification unless the `err_override` - // argument has been provided - (warnings, vec![err_override.unwrap()]) - } else { - (warnings, errors) + let h = Handler::default(); + Unifier::new(engines, help_text).unify(handler, received, expected, span); + match err_override { + Some(err_override) if h.has_errors() => { + handler.emit_err(err_override); + } + _ => { + handler.append(h); + } } } @@ -293,7 +302,7 @@ impl TypeEngine { | TypeInfo::SelfType | TypeInfo::B256 | TypeInfo::Contract - | TypeInfo::ErrorRecovery + | TypeInfo::ErrorRecovery(..) | TypeInfo::Storage { .. } | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice @@ -346,13 +355,14 @@ impl TypeEngine { | TypeInfo::SelfType | TypeInfo::B256 | TypeInfo::Contract - | TypeInfo::ErrorRecovery + | TypeInfo::ErrorRecovery(..) | TypeInfo::Storage { .. } | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice | TypeInfo::Alias { .. } => {} TypeInfo::Numeric => { - let (warnings, errors) = self.unify( + self.unify( + handler, engines, type_id, self.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), @@ -360,12 +370,6 @@ impl TypeEngine { "", None, ); - for warn in warnings { - handler.emit_warn(warn); - } - for err in errors { - handler.emit_err(err); - } } } Ok(()) @@ -484,11 +488,11 @@ impl TypeEngine { ty::GenericTypeForFunctionScope { type_id, .. }, )) => type_id, _ => { - handler.emit_err(CompileError::UnknownTypeName { + let err = handler.emit_err(CompileError::UnknownTypeName { name: call_path.to_string(), span: call_path.span(), }); - self.insert(engines, TypeInfo::ErrorRecovery) + self.insert(engines, TypeInfo::ErrorRecovery(err)) } } } @@ -504,7 +508,7 @@ impl TypeEngine { namespace, mod_path, ) - .unwrap_or_else(|_| self.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| self.insert(engines, TypeInfo::ErrorRecovery(err))); let type_id = self.insert(engines, TypeInfo::Array(elem_ty, n)); @@ -526,7 +530,7 @@ impl TypeEngine { namespace, mod_path, ) - .unwrap_or_else(|_| self.insert(engines, TypeInfo::ErrorRecovery)); + .unwrap_or_else(|err| self.insert(engines, TypeInfo::ErrorRecovery(err))); } let type_id = self.insert(engines, TypeInfo::Tuple(type_arguments)); @@ -585,12 +589,6 @@ impl TypeEngine { } } -fn normalize_err( - (w, e): (Vec, Vec), -) -> (Vec, Vec) { - (w, e.into_iter().map(CompileError::from).collect()) -} - pub(crate) trait MonomorphizeHelper { fn name(&self) -> &Ident; fn type_parameters(&self) -> &[TypeParameter]; diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 623961d2bf3..a21cae97742 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -234,7 +234,7 @@ impl ReplaceSelfType for TypeId { | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice | TypeInfo::Contract - | TypeInfo::ErrorRecovery + | TypeInfo::ErrorRecovery(_) | TypeInfo::Placeholder(_) => None, } } @@ -249,7 +249,7 @@ impl SubstTypes for TypeId { fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: &Engines) { let type_engine = engines.te(); if let Some(matching_id) = type_mapping.find_match(*self, engines) { - if !matches!(type_engine.get(matching_id), TypeInfo::ErrorRecovery) { + if !matches!(type_engine.get(matching_id), TypeInfo::ErrorRecovery(_)) { *self = matching_id; } } @@ -380,68 +380,68 @@ 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; - } + handler.scope(|handler| { + 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 - engines - .te() - .decay_numeric(handler, engines, *structure_type_id, span)?; + // resolving trait constraits require a concrete type, we need to default numeric to u64 + 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()); - if let TypeInfo::UnknownGeneric { - trait_constraints, .. - } = &structure_type_info - { - let mut generic_trait_constraints_trait_names: Vec> = vec![]; - for trait_constraint in trait_constraints.iter() { - generic_trait_constraints_trait_names.push(trait_constraint.trait_name.clone()); - } - for structure_trait_constraint in structure_trait_constraints { - if !generic_trait_constraints_trait_names - .contains(&structure_trait_constraint.trait_name) - { - error_emitted = - Some(handler.emit_err(CompileError::TraitConstraintMissing { + let structure_type_info = engines.te().get(*structure_type_id); + let structure_type_info_with_engines = + engines.help_out(structure_type_info.clone()); + if let TypeInfo::UnknownGeneric { + trait_constraints, .. + } = &structure_type_info + { + let mut generic_trait_constraints_trait_names: Vec> = + vec![]; + for trait_constraint in trait_constraints.iter() { + generic_trait_constraints_trait_names + .push(trait_constraint.trait_name.clone()); + } + for structure_trait_constraint in structure_trait_constraints { + if !generic_trait_constraints_trait_names + .contains(&structure_trait_constraint.trait_name) + { + handler.emit_err(CompileError::TraitConstraintMissing { param: structure_type_info_with_engines.to_string(), - trait_name: - structure_trait_constraint.trait_name.suffix.to_string(), + trait_name: structure_trait_constraint + .trait_name + .suffix + .to_string(), span: span.clone(), - })); + }); + } } - } - } else { - let generic_trait_constraints_trait_names = ctx - .namespace - .implemented_traits - .get_trait_names_for_type(engines, *structure_type_id); - for structure_trait_constraint in structure_trait_constraints { - if !generic_trait_constraints_trait_names.contains( - &structure_trait_constraint - .trait_name - .to_fullpath(ctx.namespace), - ) { - error_emitted = - Some(handler.emit_err(CompileError::TraitConstraintNotSatisfied { + } else { + let generic_trait_constraints_trait_names = ctx + .namespace + .implemented_traits + .get_trait_names_for_type(engines, *structure_type_id); + for structure_trait_constraint in structure_trait_constraints { + if !generic_trait_constraints_trait_names.contains( + &structure_trait_constraint + .trait_name + .to_fullpath(ctx.namespace), + ) { + handler.emit_err(CompileError::TraitConstraintNotSatisfied { ty: structure_type_info_with_engines.to_string(), - trait_name: - structure_trait_constraint.trait_name.suffix.to_string(), + trait_name: structure_trait_constraint + .trait_name + .suffix + .to_string(), span: span.clone(), - })); + }); + } } } } - } - - if let Some(err) = error_emitted { - Err(err) - } else { Ok(()) - } + }) } } diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 711db7ab1d2..1d82ebb02fc 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -128,7 +128,7 @@ pub enum TypeInfo { Numeric, Contract, // used for recovering from errors in the ast - ErrorRecovery, + ErrorRecovery(ErrorEmitted), // Static, constant size arrays. Array(TypeArgument, Length), /// Represents the entire storage declaration struct @@ -223,7 +223,7 @@ impl HashWithEngines for TypeInfo { | TypeInfo::Boolean | TypeInfo::B256 | TypeInfo::Contract - | TypeInfo::ErrorRecovery + | TypeInfo::ErrorRecovery(_) | TypeInfo::Unknown | TypeInfo::SelfType | TypeInfo::RawUntypedPtr @@ -451,7 +451,7 @@ impl DisplayWithEngines for TypeInfo { B256 => "b256".into(), Numeric => "numeric".into(), Contract => "contract".into(), - ErrorRecovery => "unknown".into(), + ErrorRecovery(_) => "unknown".into(), Enum(decl_ref) => { let decl = engines.de().get_enum(decl_ref); print_inner_types( @@ -519,7 +519,7 @@ impl DebugWithEngines for TypeInfo { B256 => "b256".into(), Numeric => "numeric".into(), Contract => "contract".into(), - ErrorRecovery => "unknown due to error".into(), + ErrorRecovery(_) => "unknown due to error".into(), Enum(decl_ref) => { let decl = engines.de().get_enum(decl_ref); print_inner_types_debug( @@ -588,7 +588,7 @@ impl TypeInfo { TypeInfo::B256 => 12, TypeInfo::Numeric => 13, TypeInfo::Contract => 14, - TypeInfo::ErrorRecovery => 15, + TypeInfo::ErrorRecovery(_) => 15, TypeInfo::Array(_, _) => 16, TypeInfo::Storage { .. } => 17, TypeInfo::RawUntypedPtr => 18, @@ -874,7 +874,7 @@ impl TypeInfo { .get(elem_ty.type_id) .can_safely_ignore(type_engine, decl_engine) } - TypeInfo::ErrorRecovery => true, + TypeInfo::ErrorRecovery(_) => true, TypeInfo::Unknown => true, _ => false, } @@ -953,7 +953,7 @@ impl TypeInfo { | TypeInfo::Ptr(..) | TypeInfo::Slice(..) | TypeInfo::Contract - | TypeInfo::ErrorRecovery + | TypeInfo::ErrorRecovery(_) | TypeInfo::Array(_, _) | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) @@ -1020,10 +1020,7 @@ impl TypeInfo { "matching on this type is unsupported right now", span.clone(), ))), - TypeInfo::ErrorRecovery => { - // return an error but don't create a new error message - Err(ErrorEmitted) - } + TypeInfo::ErrorRecovery(err) => Err(*err), } } @@ -1061,10 +1058,7 @@ impl TypeInfo { "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(ErrorEmitted) - } + TypeInfo::ErrorRecovery(err) => Err(*err), } } @@ -1117,7 +1111,7 @@ impl TypeInfo { | TypeInfo::B256 | TypeInfo::Numeric | TypeInfo::Contract - | TypeInfo::ErrorRecovery => {} + | TypeInfo::ErrorRecovery(_) => {} TypeInfo::Enum(enum_ref) => { let enum_decl = decl_engine.get_enum(enum_ref); for type_param in enum_decl.type_parameters.iter() { @@ -1296,7 +1290,9 @@ impl TypeInfo { let type_engine = engines.te(); let decl_engine = engines.de(); match (self, subfields.split_first()) { - (TypeInfo::Struct { .. } | TypeInfo::Alias { .. }, None) => Err(ErrorEmitted), + (TypeInfo::Struct { .. } | TypeInfo::Alias { .. }, None) => { + panic!("Trying to apply an empty list of subfields"); + } (TypeInfo::Struct(decl_ref), Some((first, rest))) => { let decl = decl_engine.get_struct(decl_ref); let field = match decl @@ -1338,10 +1334,7 @@ impl TypeInfo { ) => type_engine .get(*type_id) .apply_subfields(handler, engines, subfields, span), - (TypeInfo::ErrorRecovery, _) => { - // dont create a new error in this case - Err(ErrorEmitted) - } + (TypeInfo::ErrorRecovery(err), _) => Err(*err), (type_info, _) => Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { actually: format!("{:?}", engines.help_out(type_info)), span: span.clone(), @@ -1369,7 +1362,7 @@ impl TypeInfo { | TypeInfo::RawUntypedSlice | TypeInfo::Ptr(..) | TypeInfo::Slice(..) - | TypeInfo::ErrorRecovery => false, + | TypeInfo::ErrorRecovery(_) => false, TypeInfo::Unknown | TypeInfo::UnknownGeneric { .. } | TypeInfo::ContractCaller { .. } @@ -1433,7 +1426,7 @@ impl TypeInfo { .get(*type_id) .expect_tuple(handler, engines, debug_string, debug_span) } - TypeInfo::ErrorRecovery => Err(ErrorEmitted), + TypeInfo::ErrorRecovery(err) => Err(*err), a => Err(handler.emit_err(CompileError::NotATuple { name: debug_string.into(), span: debug_span.clone(), @@ -1474,7 +1467,7 @@ impl TypeInfo { .te() .get(*type_id) .expect_enum(handler, engines, debug_string, debug_span), - TypeInfo::ErrorRecovery => Err(ErrorEmitted), + TypeInfo::ErrorRecovery(err) => Err(*err), a => Err(handler.emit_err(CompileError::NotAnEnum { name: debug_string.into(), span: debug_span.clone(), @@ -1515,7 +1508,7 @@ impl TypeInfo { .te() .get(*type_id) .expect_struct(handler, engines, debug_span), - TypeInfo::ErrorRecovery => Err(ErrorEmitted), + TypeInfo::ErrorRecovery(err) => Err(*err), 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/mod.rs b/sway-core/src/type_system/mod.rs index 00ddad6d246..e351e76981a 100644 --- a/sway-core/src/type_system/mod.rs +++ b/sway-core/src/type_system/mod.rs @@ -7,6 +7,8 @@ mod substitute; mod unify; pub use priv_prelude::*; +#[cfg(test)] +use sway_error::handler::Handler; #[cfg(test)] use crate::{language::ty::TyEnumDecl, transform::AttributesMap}; @@ -118,7 +120,9 @@ fn generic_enum_resolution() { let ty_2 = engines.te().insert(&engines, TypeInfo::Enum(decl_ref_2)); // Unify them together... - let (_, errors) = engines.te().unify(&engines, ty_1, ty_2, &sp, "", None); + let h = Handler::default(); + engines.te().unify(&h, &engines, ty_1, ty_2, &sp, "", None); + let (_, errors) = h.consume(); assert!(errors.is_empty()); if let TypeInfo::Enum(decl_ref_1) = engines.te().get(ty_1) { @@ -146,7 +150,9 @@ fn basic_numeric_unknown() { .insert(&engines, TypeInfo::UnsignedInteger(IntegerBits::Eight)); // Unify them together... - let (_, errors) = engines.te().unify(&engines, id, id2, &sp, "", None); + let h = Handler::default(); + engines.te().unify(&h, &engines, id, id2, &sp, "", None); + let (_, errors) = h.consume(); assert!(errors.is_empty()); assert!(matches!( @@ -168,7 +174,9 @@ fn unify_numerics() { .insert(&engines, TypeInfo::UnsignedInteger(IntegerBits::Eight)); // Unify them together... - let (_, errors) = engines.te().unify(&engines, id2, id, &sp, "", None); + let h = Handler::default(); + engines.te().unify(&h, &engines, id2, id, &sp, "", None); + let (_, errors) = h.consume(); assert!(errors.is_empty()); assert!(matches!( @@ -189,7 +197,9 @@ fn unify_numerics_2() { let id2 = type_engine.insert(&engines, TypeInfo::UnsignedInteger(IntegerBits::Eight)); // Unify them together... - let (_, errors) = type_engine.unify(&engines, id, id2, &sp, "", None); + let h = Handler::default(); + type_engine.unify(&h, &engines, id, id2, &sp, "", None); + let (_, errors) = h.consume(); assert!(errors.is_empty()); assert!(matches!( diff --git a/sway-core/src/type_system/substitute/subst_map.rs b/sway-core/src/type_system/substitute/subst_map.rs index 56e192b5387..e60253247f7 100644 --- a/sway-core/src/type_system/substitute/subst_map.rs +++ b/sway-core/src/type_system/substitute/subst_map.rs @@ -246,7 +246,7 @@ impl TypeSubstMap { | (TypeInfo::B256, TypeInfo::B256) | (TypeInfo::Numeric, TypeInfo::Numeric) | (TypeInfo::Contract, TypeInfo::Contract) - | (TypeInfo::ErrorRecovery, TypeInfo::ErrorRecovery) + | (TypeInfo::ErrorRecovery(_), TypeInfo::ErrorRecovery(_)) | (TypeInfo::Str(_), TypeInfo::Str(_)) | (TypeInfo::UnsignedInteger(_), TypeInfo::UnsignedInteger(_)) | (TypeInfo::ContractCaller { .. }, TypeInfo::ContractCaller { .. }) => TypeSubstMap { @@ -433,7 +433,7 @@ impl TypeSubstMap { | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice | TypeInfo::Contract - | TypeInfo::ErrorRecovery => None, + | TypeInfo::ErrorRecovery(..) => None, } } } diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index f75aa1ecdbd..3fe3e830389 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -1,6 +1,6 @@ use std::fmt; -use sway_error::{type_error::TypeError, warning::CompileWarning}; +use sway_error::{handler::Handler, type_error::TypeError}; use sway_types::{Ident, Span}; use crate::{engine_threading::*, language::ty, type_system::priv_prelude::*}; @@ -25,54 +25,59 @@ impl<'a> Unifier<'a> { /// Helper method for replacing the values in the [TypeEngine]. fn replace_received_with_expected( &self, + handler: &Handler, received: TypeId, expected: TypeId, received_type_info: &TypeInfo, expected_type_info: TypeInfo, span: &Span, - ) -> (Vec, Vec) { - match self.engines.te().slab.replace( - received, - received_type_info, - expected_type_info, - self.engines, - ) { - None => (vec![], vec![]), - Some(_) => self.unify(received, expected, span), + ) { + let type_engine = self.engines.te(); + if type_engine + .slab + .replace( + received, + received_type_info, + expected_type_info, + self.engines, + ) + .is_some() + { + self.unify(handler, received, expected, span); } } /// Helper method for replacing the values in the [TypeEngine]. fn replace_expected_with_received( &self, + handler: &Handler, received: TypeId, expected: TypeId, received_type_info: TypeInfo, expected_type_info: &TypeInfo, span: &Span, - ) -> (Vec, Vec) { - match self.engines.te().slab.replace( - expected, - expected_type_info, - received_type_info, - self.engines, - ) { - None => (vec![], vec![]), - Some(_) => self.unify(received, expected, span), + ) { + let type_engine = self.engines.te(); + if type_engine + .slab + .replace( + expected, + expected_type_info, + received_type_info, + self.engines, + ) + .is_some() + { + self.unify(handler, received, expected, span); } } /// Performs type unification with `received` and `expected`. - pub(crate) fn unify( - &self, - received: TypeId, - expected: TypeId, - span: &Span, - ) -> (Vec, Vec) { + pub(crate) fn unify(&self, handler: &Handler, received: TypeId, expected: TypeId, span: &Span) { use TypeInfo::*; if received == expected { - return (vec![], vec![]); + return; } match ( @@ -81,23 +86,28 @@ impl<'a> Unifier<'a> { ) { // If they have the same `TypeInfo`, then we either compare them for // correctness or perform further unification. - (Boolean, Boolean) => (vec![], vec![]), - (SelfType, SelfType) => (vec![], vec![]), - (B256, B256) => (vec![], vec![]), - (Numeric, Numeric) => (vec![], vec![]), - (Contract, Contract) => (vec![], vec![]), - (RawUntypedPtr, RawUntypedPtr) => (vec![], vec![]), - (RawUntypedSlice, RawUntypedSlice) => (vec![], vec![]), - (Str(l), Str(r)) => self.unify_strs(received, expected, span, l.val(), r.val()), - (Tuple(rfs), Tuple(efs)) if rfs.len() == efs.len() => self.unify_tuples(rfs, efs), + (Boolean, Boolean) => (), + (SelfType, SelfType) => (), + (B256, B256) => (), + (Numeric, Numeric) => (), + (Contract, Contract) => (), + (RawUntypedPtr, RawUntypedPtr) => (), + (RawUntypedSlice, RawUntypedSlice) => (), + (Str(l), Str(r)) => { + self.unify_strs(handler, received, expected, span, l.val(), r.val()) + } + (Tuple(rfs), Tuple(efs)) if rfs.len() == efs.len() => { + self.unify_tuples(handler, rfs, efs) + } (Array(re, rc), Array(ee, ec)) if rc.val() == ec.val() => { - self.unify_arrays(received, expected, span, re.type_id, ee.type_id) + self.unify_arrays(handler, received, expected, span, re.type_id, ee.type_id) } (Struct(r_decl_ref), Struct(e_decl_ref)) => { let r_decl = self.engines.de().get_struct(&r_decl_ref); let e_decl = self.engines.de().get_struct(&e_decl_ref); self.unify_structs( + handler, received, expected, span, @@ -115,20 +125,19 @@ impl<'a> Unifier<'a> { } // Type aliases and the types they encapsulate coerce to each other. - (Alias { ty, .. }, _) => self.unify(ty.type_id, expected, span), - (_, Alias { ty, .. }) => self.unify(received, ty.type_id, span), + (Alias { ty, .. }, _) => self.unify(handler, ty.type_id, expected, span), + (_, Alias { ty, .. }) => self.unify(handler, received, ty.type_id, span), // Let empty enums to coerce to any other type. This is useful for Never enum. (Enum(r_decl_ref), _) - if self.engines.de().get_enum(&r_decl_ref).variants.is_empty() => - { - (vec![], vec![]) - } + if self.engines.de().get_enum(&r_decl_ref).variants.is_empty() => {} + (Enum(r_decl_ref), Enum(e_decl_ref)) => { let r_decl = self.engines.de().get_enum(&r_decl_ref); let e_decl = self.engines.de().get_enum(&e_decl_ref); self.unify_enums( + handler, received, expected, span, @@ -147,12 +156,12 @@ impl<'a> Unifier<'a> { // For integers and numerics, we (potentially) unify the numeric // with the integer. - (UnsignedInteger(r), UnsignedInteger(e)) if r == e => (vec![], vec![]), + (UnsignedInteger(r), UnsignedInteger(e)) if r == e => (), (Numeric, e @ UnsignedInteger(_)) => { - self.replace_received_with_expected(received, expected, &Numeric, e, span) + self.replace_received_with_expected(handler, received, expected, &Numeric, e, span) } (r @ UnsignedInteger(_), Numeric) => { - self.replace_expected_with_received(received, expected, r, &Numeric, span) + self.replace_expected_with_received(handler, received, expected, r, &Numeric, span) } // For contract callers, we (potentially) unify them if they have @@ -168,6 +177,7 @@ impl<'a> Unifier<'a> { ) if (ran == ean && rra.is_none()) || matches!(ran, AbiName::Deferred) => { // if one address is empty, coerce to the other one self.replace_received_with_expected( + handler, received, expected, r, @@ -186,6 +196,7 @@ impl<'a> Unifier<'a> { ) if (ran == ean && ea.is_none()) || matches!(ean, AbiName::Deferred) => { // if one address is empty, coerce to the other one self.replace_expected_with_received( + handler, received, expected, self.engines.te().slab.get(received.index()), @@ -197,28 +208,27 @@ impl<'a> Unifier<'a> { if r.eq(e, self.engines) => { // if they are the same, then it's ok - (vec![], vec![]) } // When we don't know anything about either term, assume that // they match and make the one we know nothing about reference the // one we may know something about. - (Unknown, Unknown) => (vec![], vec![]), + (Unknown, Unknown) => (), (Unknown, e) => { - self.replace_received_with_expected(received, expected, &Unknown, e, span) + self.replace_received_with_expected(handler, received, expected, &Unknown, e, span) } (r, Unknown) => { - self.replace_expected_with_received(received, expected, r, &Unknown, span) + self.replace_expected_with_received(handler, received, expected, r, &Unknown, span) } (r @ Placeholder(_), e @ Placeholder(_)) => { - self.replace_expected_with_received(received, expected, r, &e, span) + self.replace_expected_with_received(handler, received, expected, r, &e, span) } (r @ Placeholder(_), e) => { - self.replace_received_with_expected(received, expected, &r, e, span) + self.replace_received_with_expected(handler, received, expected, &r, e, span) } (r, e @ Placeholder(_)) => { - self.replace_expected_with_received(received, expected, r, &e, span) + self.replace_expected_with_received(handler, received, expected, r, &e, span) } // Generics are handled similarly to the case for unknowns, except @@ -233,26 +243,28 @@ impl<'a> Unifier<'a> { name: en, trait_constraints: etc, }, - ) if rn.as_str() == en.as_str() && rtc.eq(&etc, self.engines) => (vec![], vec![]), + ) if rn.as_str() == en.as_str() && rtc.eq(&etc, self.engines) => (), (r @ UnknownGeneric { .. }, e) if !self.occurs_check(r.clone(), &e) => { - self.replace_received_with_expected(received, expected, &r, e, span) + self.replace_received_with_expected(handler, received, expected, &r, e, span) } (r, e @ UnknownGeneric { .. }) if !self.occurs_check(e.clone(), &r) => { - self.replace_expected_with_received(received, expected, r, &e, span) + self.replace_expected_with_received(handler, received, expected, r, &e, span) } // If no previous attempts to unify were successful, raise an error. - (TypeInfo::ErrorRecovery, _) => (vec![], vec![]), - (_, TypeInfo::ErrorRecovery) => (vec![], vec![]), + (TypeInfo::ErrorRecovery(_), _) => (), + (_, TypeInfo::ErrorRecovery(_)) => (), (r, e) => { let (received, expected) = self.assign_args(r, e); - let errors = vec![TypeError::MismatchedType { - expected, - received, - help_text: self.help_text.clone(), - span: span.clone(), - }]; - (vec![], errors) + handler.emit_err( + TypeError::MismatchedType { + expected, + received, + help_text: self.help_text.clone(), + span: span.clone(), + } + .into(), + ); } } } @@ -263,136 +275,138 @@ impl<'a> Unifier<'a> { fn unify_strs( &self, + handler: &Handler, received: TypeId, expected: TypeId, span: &Span, r: usize, e: usize, - ) -> (Vec, Vec) { - let warnings = vec![]; - let mut errors = vec![]; + ) { if r != e { let (received, expected) = self.assign_args(received, expected); - errors.push(TypeError::MismatchedType { - expected, - received, - help_text: self.help_text.clone(), - span: span.clone(), - }); + handler.emit_err( + TypeError::MismatchedType { + expected, + received, + help_text: self.help_text.clone(), + span: span.clone(), + } + .into(), + ); } - (warnings, errors) } - fn unify_tuples( - &self, - rfs: Vec, - efs: Vec, - ) -> (Vec, Vec) { - let mut warnings = vec![]; - let mut errors = vec![]; + fn unify_tuples(&self, handler: &Handler, rfs: Vec, efs: Vec) { for (rf, ef) in rfs.iter().zip(efs.iter()) { - let (mut warns, mut errs) = self.unify(rf.type_id, ef.type_id, &rf.span); - warnings.append(&mut warns); - errors.append(&mut errs); + self.unify(handler, rf.type_id, ef.type_id, &rf.span); } - (warnings, errors) } fn unify_structs( &self, + handler: &Handler, received: TypeId, expected: TypeId, span: &Span, r: (Ident, Vec, Vec), e: (Ident, Vec, Vec), - ) -> (Vec, Vec) { - let mut warnings = vec![]; - let mut errors = vec![]; + ) { let (rn, rtps, rfs) = r; 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)| { - 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); + self.unify( + handler, + rf.type_argument.type_id, + ef.type_argument.type_id, + span, + ); }); rtps.iter().zip(etps.iter()).for_each(|(rtp, etp)| { - let (mut warns, mut errs) = self.unify(rtp.type_id, etp.type_id, span); - warnings.append(&mut warns); - errors.append(&mut errs); + self.unify(handler, rtp.type_id, etp.type_id, span); }); } else { let (received, expected) = self.assign_args(received, expected); - errors.push(TypeError::MismatchedType { - expected, - received, - help_text: self.help_text.clone(), - span: span.clone(), - }); + handler.emit_err( + TypeError::MismatchedType { + expected, + received, + help_text: self.help_text.clone(), + span: span.clone(), + } + .into(), + ); } - (warnings, errors) } fn unify_enums( &self, + handler: &Handler, received: TypeId, expected: TypeId, span: &Span, r: (Ident, Vec, Vec), e: (Ident, Vec, Vec), - ) -> (Vec, Vec) { - let mut warnings = vec![]; - let mut errors = vec![]; + ) { let (rn, rtps, rvs) = r; 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)| { - 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); + self.unify( + handler, + rv.type_argument.type_id, + ev.type_argument.type_id, + span, + ); }); rtps.iter().zip(etps.iter()).for_each(|(rtp, etp)| { - let (mut warns, mut errs) = self.unify(rtp.type_id, etp.type_id, span); - warnings.append(&mut warns); - errors.append(&mut errs); + self.unify(handler, rtp.type_id, etp.type_id, span); }); } else { let (received, expected) = self.assign_args(received, expected); - errors.push(TypeError::MismatchedType { - expected, - received, - help_text: self.help_text.clone(), - span: span.clone(), - }); + handler.emit_err( + TypeError::MismatchedType { + expected, + received, + help_text: self.help_text.clone(), + span: span.clone(), + } + .into(), + ); } - (warnings, errors) } fn unify_arrays( &self, + handler: &Handler, received: TypeId, expected: TypeId, span: &Span, r: TypeId, e: TypeId, - ) -> (Vec, Vec) { - let (warnings, new_errors) = self.unify(r, e, span); + ) { + let h = Handler::default(); + self.unify(&h, r, e, span); + let (new_errors, warnings) = h.consume(); // If there was an error then we want to report the array types as mismatching, not // the elem types. - let mut errors = vec![]; if !new_errors.is_empty() { let (received, expected) = self.assign_args(received, expected); - errors.push(TypeError::MismatchedType { - expected, - received, - help_text: self.help_text.clone(), - span: span.clone(), - }); + handler.emit_err( + TypeError::MismatchedType { + expected, + received, + help_text: self.help_text.clone(), + span: span.clone(), + } + .into(), + ); + } + + for warn in warnings { + handler.emit_warn(warn); } - (warnings, errors) } fn assign_args(&self, r: T, e: T) -> (String, String) diff --git a/sway-core/src/type_system/unify/unify_check.rs b/sway-core/src/type_system/unify/unify_check.rs index 6cc9ca88450..8134b3b94ef 100644 --- a/sway-core/src/type_system/unify/unify_check.rs +++ b/sway-core/src/type_system/unify/unify_check.rs @@ -379,8 +379,8 @@ impl<'a> UnifyCheck<'a> { || matches!(ean, AbiName::Deferred) } - (ErrorRecovery, _) => true, - (_, ErrorRecovery) => true, + (ErrorRecovery(_), _) => true, + (_, ErrorRecovery(_)) => true, (a, b) => a.eq(&b, self.engines), } @@ -454,7 +454,7 @@ impl<'a> UnifyCheck<'a> { (TypeInfo::Contract, TypeInfo::Contract) => true, (TypeInfo::Boolean, TypeInfo::Boolean) => true, (TypeInfo::B256, TypeInfo::B256) => true, - (TypeInfo::ErrorRecovery, TypeInfo::ErrorRecovery) => true, + (TypeInfo::ErrorRecovery(_), TypeInfo::ErrorRecovery(_)) => true, (TypeInfo::Str(l), TypeInfo::Str(r)) => l.val() == r.val(), (TypeInfo::UnsignedInteger(l), TypeInfo::UnsignedInteger(r)) => l == r, (TypeInfo::RawUntypedPtr, TypeInfo::RawUntypedPtr) => true, diff --git a/sway-error/Cargo.toml b/sway-error/Cargo.toml index e877c8fe7b9..605a624a260 100644 --- a/sway-error/Cargo.toml +++ b/sway-error/Cargo.toml @@ -9,10 +9,7 @@ license.workspace = true repository.workspace = true [dependencies] -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 25c7cb940bd..ee6472fe026 100644 --- a/sway-error/src/handler.rs +++ b/sway-error/src/handler.rs @@ -31,7 +31,7 @@ impl Handler { /// Emit the error `err`. pub fn emit_err(&self, err: CompileError) -> ErrorEmitted { self.inner.borrow_mut().errors.push(err); - ErrorEmitted + ErrorEmitted { _priv: () } } /// Emit the warning `warn`. @@ -39,14 +39,31 @@ impl Handler { self.inner.borrow_mut().warnings.push(warn); } - pub fn has_error(&self) -> bool { + pub fn has_errors(&self) -> bool { !self.inner.borrow().errors.is_empty() } - pub fn has_warning(&self) -> bool { + pub fn has_warnings(&self) -> bool { !self.inner.borrow().warnings.is_empty() } + pub fn scope( + &self, + f: impl FnOnce(&Handler) -> Result, + ) -> Result { + let scoped_handler = Handler::default(); + let closure_res = f(&scoped_handler); + let had_errors = scoped_handler.has_errors(); + + self.append(scoped_handler); + + if had_errors { + Err(ErrorEmitted { _priv: () }) + } else { + closure_res + } + } + /// Extract all the errors from this handler. pub fn consume(self) -> (Vec, Vec) { let inner = self.inner.into_inner(); @@ -71,8 +88,10 @@ impl Handler { } /// Proof that an error was emitted through a `Handler`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ErrorEmitted; +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct ErrorEmitted { + _priv: (), +} /// We want compile errors and warnings to retain their ordering, since typically /// they are grouped by relevance. However, we want to deduplicate them. diff --git a/sway-error/src/lex_error.rs b/sway-error/src/lex_error.rs index e43e45ead4e..a1ffd183592 100644 --- a/sway-error/src/lex_error.rs +++ b/sway-error/src/lex_error.rs @@ -1,5 +1,4 @@ -use sway_ast::token::Delimiter; -use sway_types::{Ident, Span, Spanned}; +use sway_types::{ast::Delimiter, Ident, Span, Spanned}; use thiserror::Error; #[derive(Error, Debug, Clone, PartialEq, Eq, PartialOrd, Hash)] diff --git a/sway-error/src/parser_error.rs b/sway-error/src/parser_error.rs index a000ce82d64..c61eda1e819 100644 --- a/sway-error/src/parser_error.rs +++ b/sway-error/src/parser_error.rs @@ -1,4 +1,4 @@ -use sway_ast::token::PunctKind; +use sway_types::ast::PunctKind; use sway_types::{Ident, Span}; use thiserror::Error; diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index fd6474bbbff..e640ec06b21 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -217,7 +217,7 @@ impl Session { } = value.unwrap(); // Get a reference to the typed program AST. - let typed_program = typed.as_ref().ok_or_else(|| { + let typed_program = typed.as_ref().ok().ok_or_else(|| { *diagnostics = get_diagnostics(&warnings, &errors); LanguageServerError::FailedToParse })?; diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 271f15de592..a2bccdc7225 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -165,7 +165,7 @@ impl Parse for UseStatement { impl Parse for Expression { fn parse(&self, ctx: &ParseContext) { match &self.kind { - ExpressionKind::Error(part_spans) => { + ExpressionKind::Error(part_spans, _) => { for span in part_spans.iter() { ctx.tokens.insert( to_ident_key(&Ident::new(span.clone())), diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index ddcea7e52d9..fa47e206a72 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -84,7 +84,7 @@ impl Parse for ty::TyDecl { ty::TyDecl::ImplTrait(decl) => decl.parse(ctx), ty::TyDecl::AbiDecl(decl) => decl.parse(ctx), ty::TyDecl::GenericTypeForFunctionScope(decl) => decl.parse(ctx), - ty::TyDecl::ErrorRecovery(_) => {} + ty::TyDecl::ErrorRecovery(_, _) => {} ty::TyDecl::StorageDecl(decl) => decl.parse(ctx), ty::TyDecl::TypeAliasDecl(decl) => decl.parse(ctx), } diff --git a/sway-parse/src/brackets.rs b/sway-parse/src/brackets.rs index 75777496e36..04121b7426b 100644 --- a/sway-parse/src/brackets.rs +++ b/sway-parse/src/brackets.rs @@ -2,10 +2,9 @@ use crate::{Parse, ParseResult, ParseToEnd, Parser}; use sway_ast::brackets::{Braces, Parens, SquareBrackets}; use sway_ast::keywords::{CloseAngleBracketToken, OpenAngleBracketToken}; -use sway_ast::token::Delimiter; use sway_error::handler::ErrorEmitted; use sway_error::parser_error::ParseErrorKind; -use sway_types::{Span, Spanned}; +use sway_types::{ast::Delimiter, Span, Spanned}; pub trait ParseBracket: Sized { fn try_parse(parser: &mut Parser) -> ParseResult> diff --git a/sway-parse/src/expr/mod.rs b/sway-parse/src/expr/mod.rs index 810440472b6..fd84dbe2211 100644 --- a/sway-parse/src/expr/mod.rs +++ b/sway-parse/src/expr/mod.rs @@ -10,14 +10,13 @@ use sway_ast::keywords::{ }; use sway_ast::literal::{LitBool, LitBoolType}; use sway_ast::punctuated::Punctuated; -use sway_ast::token::Delimiter; use sway_ast::{ AbiCastArgs, CodeBlockContents, Expr, ExprArrayDescriptor, ExprStructField, ExprTupleDescriptor, GenericArgs, IfCondition, IfExpr, LitInt, Literal, MatchBranch, MatchBranchKind, PathExpr, PathExprSegment, Statement, StatementLet, }; use sway_error::parser_error::ParseErrorKind; -use sway_types::{Ident, Span, Spanned}; +use sway_types::{ast::Delimiter, Ident, Span, Spanned}; mod asm; pub mod op_code; @@ -104,7 +103,7 @@ impl Parse for StatementLet { // Recover on missing expression. // FIXME(Centril): We should point at right after `=`, not at it. - let on_err = |_| Expr::Error([eq_token.span()].into()); + let on_err = |err| Expr::Error([eq_token.span()].into(), err); let expr = parser.parse().unwrap_or_else(on_err); // Recover on missing semicolon. @@ -586,8 +585,8 @@ fn parse_projection(parser: &mut Parser, ctx: ParseExprCtx) -> ParseResult // Nothing expected followed. Now we have parsed `expr .`. // Try to recover as an unknown sort of expression. - parser.emit_error(ParseErrorKind::ExpectedFieldName); - return Ok(Expr::Error([target.span(), dot_token.span()].into())); + let err = parser.emit_error(ParseErrorKind::ExpectedFieldName); + return Ok(Expr::Error([target.span(), dot_token.span()].into(), err)); } return Ok(expr); } @@ -712,7 +711,10 @@ fn parse_atom(parser: &mut Parser, ctx: ParseExprCtx) -> ParseResult { // We tried parsing it as a path but we didn't succeed so we try to recover this // as an unknown sort of expression. This happens, for instance, when the user // types `foo::` - return Ok(Expr::Error([path.span()].into())); + return Ok(Expr::Error( + [path.span()].into(), + parser.emit_error(ParseErrorKind::ExpectedPathType), + )); } if !ctx.parsing_conditional { if let Some(fields) = Braces::try_parse(parser)? { diff --git a/sway-parse/src/parse.rs b/sway-parse/src/parse.rs index 1ea6939b4d3..3726502b567 100644 --- a/sway-parse/src/parse.rs +++ b/sway-parse/src/parse.rs @@ -1,10 +1,9 @@ use crate::keywords::RESERVED_KEYWORDS; use crate::{ParseResult, Parser, ParserConsumed, Peeker}; -use sway_ast::token::Delimiter; use sway_ast::Intrinsic; use sway_error::parser_error::ParseErrorKind; -use sway_types::{Ident, Spanned}; +use sway_types::{ast::Delimiter, Ident, Spanned}; pub trait Parse { fn parse(parser: &mut Parser) -> ParseResult diff --git a/sway-parse/src/parser.rs b/sway-parse/src/parser.rs index 3d504414f9d..46c1544517b 100644 --- a/sway-parse/src/parser.rs +++ b/sway-parse/src/parser.rs @@ -3,14 +3,15 @@ use crate::{Parse, ParseToEnd, Peek}; use core::marker::PhantomData; use sway_ast::keywords::Keyword; use sway_ast::literal::Literal; -use sway_ast::token::{ - Delimiter, DocComment, Group, Punct, PunctKind, Spacing, TokenStream, TokenTree, -}; +use sway_ast::token::{DocComment, Group, Punct, Spacing, TokenStream, TokenTree}; use sway_ast::PubToken; use sway_error::error::CompileError; use sway_error::handler::{ErrorEmitted, Handler}; use sway_error::parser_error::{ParseError, ParseErrorKind}; -use sway_types::{Ident, Span, Spanned}; +use sway_types::{ + ast::{Delimiter, PunctKind}, + Ident, Span, Spanned, +}; pub struct Parser<'a, 'e> { token_trees: &'a [TokenTree], diff --git a/sway-parse/src/pattern.rs b/sway-parse/src/pattern.rs index 66086ddfc11..5f6c600914e 100644 --- a/sway-parse/src/pattern.rs +++ b/sway-parse/src/pattern.rs @@ -75,7 +75,10 @@ fn parse_atomic_pattern(parser: &mut Parser) -> ParseResult { let path = parser.parse::()?; if path.incomplete_suffix { - return Ok(Pattern::Error(Box::new([path.span()]))); + return Ok(Pattern::Error( + Box::new([path.span()]), + parser.emit_error(ParseErrorKind::ExpectedPathType), + )); } if let Some(args) = Parens::try_parse(parser)? { return Ok(Pattern::Constructor { path, args }); diff --git a/sway-parse/src/token.rs b/sway-parse/src/token.rs index 168358561fc..d56faa7c64b 100644 --- a/sway-parse/src/token.rs +++ b/sway-parse/src/token.rs @@ -4,13 +4,16 @@ use num_bigint::BigUint; use std::sync::Arc; use sway_ast::literal::{LitChar, LitInt, LitIntType, LitString, Literal}; use sway_ast::token::{ - Comment, CommentKind, CommentedGroup, CommentedTokenStream, CommentedTokenTree, Delimiter, - DocComment, DocStyle, GenericTokenTree, Punct, PunctKind, Spacing, TokenStream, + Comment, CommentKind, CommentedGroup, CommentedTokenStream, CommentedTokenTree, DocComment, + DocStyle, GenericTokenTree, Punct, Spacing, TokenStream, }; use sway_error::error::CompileError; use sway_error::handler::{ErrorEmitted, Handler}; use sway_error::lex_error::{LexError, LexErrorKind}; -use sway_types::{Ident, SourceId, Span, Spanned}; +use sway_types::{ + ast::{Delimiter, PunctKind}, + Ident, SourceId, Span, Spanned, +}; use unicode_xid::UnicodeXID; #[extension_trait] diff --git a/sway-parse/src/ty/mod.rs b/sway-parse/src/ty/mod.rs index e83a3d63a77..fac99a93030 100644 --- a/sway-parse/src/ty/mod.rs +++ b/sway-parse/src/ty/mod.rs @@ -2,10 +2,9 @@ use crate::{Parse, ParseBracket, ParseResult, ParseToEnd, Parser, ParserConsumed use sway_ast::brackets::{Parens, SquareBrackets}; use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken}; -use sway_ast::token::Delimiter; use sway_ast::ty::{Ty, TyArrayDescriptor, TyTupleDescriptor}; use sway_error::parser_error::ParseErrorKind; -use sway_types::Ident; +use sway_types::{ast::Delimiter, Ident}; impl Parse for Ty { fn parse(parser: &mut Parser) -> ParseResult { diff --git a/sway-types/src/ast.rs b/sway-types/src/ast.rs new file mode 100644 index 00000000000..b137ad9bd09 --- /dev/null +++ b/sway-types/src/ast.rs @@ -0,0 +1,70 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Delimiter { + Parenthesis, + Brace, + Bracket, +} + +impl Delimiter { + pub fn as_open_char(self) -> char { + match self { + Delimiter::Parenthesis => '(', + Delimiter::Brace => '{', + Delimiter::Bracket => '[', + } + } + pub fn as_close_char(self) -> char { + match self { + Delimiter::Parenthesis => ')', + Delimiter::Brace => '}', + Delimiter::Bracket => ']', + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum PunctKind { + Semicolon, + Colon, + ForwardSlash, + Comma, + Star, + Add, + Sub, + LessThan, + GreaterThan, + Equals, + Dot, + Bang, + Percent, + Ampersand, + Caret, + Pipe, + Underscore, + Sharp, +} + +impl PunctKind { + pub fn as_char(&self) -> char { + match self { + PunctKind::Semicolon => ';', + PunctKind::Colon => ':', + PunctKind::ForwardSlash => '/', + PunctKind::Comma => ',', + PunctKind::Star => '*', + PunctKind::Add => '+', + PunctKind::Sub => '-', + PunctKind::LessThan => '<', + PunctKind::GreaterThan => '>', + PunctKind::Equals => '=', + PunctKind::Dot => '.', + PunctKind::Bang => '!', + PunctKind::Percent => '%', + PunctKind::Ampersand => '&', + PunctKind::Caret => '^', + PunctKind::Pipe => '|', + PunctKind::Underscore => '_', + PunctKind::Sharp => '#', + } + } +} diff --git a/sway-types/src/lib.rs b/sway-types/src/lib.rs index 3db9f4d9648..32dcd979e60 100644 --- a/sway-types/src/lib.rs +++ b/sway-types/src/lib.rs @@ -23,6 +23,8 @@ pub mod state; pub mod style; +pub mod ast; + pub type Id = [u8; Bytes32::LEN]; pub type Contract = [u8; ContractId::LEN]; diff --git a/swayfmt/src/items/item_abi.rs b/swayfmt/src/items/item_abi.rs index b84dfd38d46..32ec202d473 100644 --- a/swayfmt/src/items/item_abi.rs +++ b/swayfmt/src/items/item_abi.rs @@ -8,8 +8,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, token::Delimiter, ItemAbi}; -use sway_types::Spanned; +use sway_ast::{keywords::Token, ItemAbi}; +use sway_types::{ast::Delimiter, Spanned}; impl Format for ItemAbi { fn format( diff --git a/swayfmt/src/items/item_configurable/mod.rs b/swayfmt/src/items/item_configurable/mod.rs index 4548802394b..720cd1526fe 100644 --- a/swayfmt/src/items/item_configurable/mod.rs +++ b/swayfmt/src/items/item_configurable/mod.rs @@ -10,8 +10,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, token::Delimiter, ConfigurableField, ItemConfigurable}; -use sway_types::Spanned; +use sway_ast::{keywords::Token, ConfigurableField, ItemConfigurable}; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; diff --git a/swayfmt/src/items/item_enum/mod.rs b/swayfmt/src/items/item_enum/mod.rs index c64a0bb2913..c3de6abe099 100644 --- a/swayfmt/src/items/item_enum/mod.rs +++ b/swayfmt/src/items/item_enum/mod.rs @@ -11,11 +11,11 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{ - token::{Delimiter, PunctKind}, - ItemEnum, +use sway_ast::ItemEnum; +use sway_types::{ + ast::{Delimiter, PunctKind}, + Spanned, }; -use sway_types::Spanned; #[cfg(test)] mod tests; diff --git a/swayfmt/src/items/item_fn/mod.rs b/swayfmt/src/items/item_fn/mod.rs index 0c69453bd39..feb15856907 100644 --- a/swayfmt/src/items/item_fn/mod.rs +++ b/swayfmt/src/items/item_fn/mod.rs @@ -13,10 +13,9 @@ use crate::{ use std::fmt::Write; use sway_ast::{ keywords::{MutToken, RefToken, SelfToken, Token}, - token::Delimiter, FnArg, FnArgs, FnSignature, ItemFn, }; -use sway_types::Spanned; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; diff --git a/swayfmt/src/items/item_impl/mod.rs b/swayfmt/src/items/item_impl/mod.rs index 0a85aa8498b..d60b5d3ca70 100644 --- a/swayfmt/src/items/item_impl/mod.rs +++ b/swayfmt/src/items/item_impl/mod.rs @@ -8,8 +8,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{token::Delimiter, ItemImpl, ItemImplItem}; -use sway_types::Spanned; +use sway_ast::{ItemImpl, ItemImplItem}; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; diff --git a/swayfmt/src/items/item_storage/mod.rs b/swayfmt/src/items/item_storage/mod.rs index f62df529e84..04089779d78 100644 --- a/swayfmt/src/items/item_storage/mod.rs +++ b/swayfmt/src/items/item_storage/mod.rs @@ -11,8 +11,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, token::Delimiter, ItemStorage, StorageField}; -use sway_types::Spanned; +use sway_ast::{keywords::Token, ItemStorage, StorageField}; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; diff --git a/swayfmt/src/items/item_struct/mod.rs b/swayfmt/src/items/item_struct/mod.rs index 51206d2bf2a..174cb71765d 100644 --- a/swayfmt/src/items/item_struct/mod.rs +++ b/swayfmt/src/items/item_struct/mod.rs @@ -11,8 +11,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{token::Delimiter, ItemStruct}; -use sway_types::Spanned; +use sway_ast::ItemStruct; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; diff --git a/swayfmt/src/items/item_trait/mod.rs b/swayfmt/src/items/item_trait/mod.rs index b725494dd98..0bee997165b 100644 --- a/swayfmt/src/items/item_trait/mod.rs +++ b/swayfmt/src/items/item_trait/mod.rs @@ -8,8 +8,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, token::Delimiter, ItemTrait, ItemTraitItem, Traits}; -use sway_types::Spanned; +use sway_ast::{keywords::Token, ItemTrait, ItemTraitItem, Traits}; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; diff --git a/swayfmt/src/items/item_use/mod.rs b/swayfmt/src/items/item_use/mod.rs index e452522fe35..ec68d9ce243 100644 --- a/swayfmt/src/items/item_use/mod.rs +++ b/swayfmt/src/items/item_use/mod.rs @@ -9,11 +9,11 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{ - token::{Delimiter, PunctKind}, - ItemUse, UseTree, +use sway_ast::{ItemUse, UseTree}; +use sway_types::{ + ast::{Delimiter, PunctKind}, + Spanned, }; -use sway_types::Spanned; #[cfg(test)] mod tests; diff --git a/swayfmt/src/utils/language/attribute.rs b/swayfmt/src/utils/language/attribute.rs index 44442f15385..4b86dcd2dd1 100644 --- a/swayfmt/src/utils/language/attribute.rs +++ b/swayfmt/src/utils/language/attribute.rs @@ -6,11 +6,12 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{ - attribute::{Annotated, Attribute, AttributeArg, AttributeDecl, AttributeHashKind}, - token::{Delimiter, PunctKind}, +use sway_ast::attribute::{Annotated, Attribute, AttributeArg, AttributeDecl, AttributeHashKind}; +use sway_types::{ + ast::{Delimiter, PunctKind}, + constants::DOC_COMMENT_ATTRIBUTE_NAME, + Spanned, }; -use sway_types::{constants::DOC_COMMENT_ATTRIBUTE_NAME, Spanned}; impl Format for Annotated { fn format( diff --git a/swayfmt/src/utils/language/expr/abi_cast.rs b/swayfmt/src/utils/language/expr/abi_cast.rs index 8273c2d4b45..14493f3f4d3 100644 --- a/swayfmt/src/utils/language/expr/abi_cast.rs +++ b/swayfmt/src/utils/language/expr/abi_cast.rs @@ -6,8 +6,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{token::Delimiter, AbiCastArgs}; -use sway_types::Spanned; +use sway_ast::AbiCastArgs; +use sway_types::{ast::Delimiter, Spanned}; impl Format for AbiCastArgs { fn format( diff --git a/swayfmt/src/utils/language/expr/asm_block.rs b/swayfmt/src/utils/language/expr/asm_block.rs index 93a69d9e821..96885ac7dd7 100644 --- a/swayfmt/src/utils/language/expr/asm_block.rs +++ b/swayfmt/src/utils/language/expr/asm_block.rs @@ -9,10 +9,9 @@ use crate::{ use std::fmt::Write; use sway_ast::{ expr::asm::{AsmBlock, AsmBlockContents, AsmFinalExpr, AsmRegisterDeclaration}, - token::Delimiter, Instruction, }; -use sway_types::Spanned; +use sway_types::{ast::Delimiter, Spanned}; impl Format for AsmBlock { fn format( diff --git a/swayfmt/src/utils/language/expr/code_block.rs b/swayfmt/src/utils/language/expr/code_block.rs index ec9088af4f8..5d44d485283 100644 --- a/swayfmt/src/utils/language/expr/code_block.rs +++ b/swayfmt/src/utils/language/expr/code_block.rs @@ -7,7 +7,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{token::Delimiter, CodeBlockContents}; +use sway_ast::CodeBlockContents; +use sway_types::ast::Delimiter; impl Format for CodeBlockContents { fn format( diff --git a/swayfmt/src/utils/language/expr/collections.rs b/swayfmt/src/utils/language/expr/collections.rs index 804cfe5e53c..078298183d4 100644 --- a/swayfmt/src/utils/language/expr/collections.rs +++ b/swayfmt/src/utils/language/expr/collections.rs @@ -6,8 +6,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{token::Delimiter, ExprArrayDescriptor, ExprTupleDescriptor}; -use sway_types::Spanned; +use sway_ast::{ExprArrayDescriptor, ExprTupleDescriptor}; +use sway_types::{ast::Delimiter, Spanned}; impl Format for ExprTupleDescriptor { fn format( diff --git a/swayfmt/src/utils/language/expr/conditional.rs b/swayfmt/src/utils/language/expr/conditional.rs index 5fab43d88e0..de6c06f4923 100644 --- a/swayfmt/src/utils/language/expr/conditional.rs +++ b/swayfmt/src/utils/language/expr/conditional.rs @@ -10,10 +10,8 @@ use crate::{ }, }; use std::{fmt::Write, ops::Range}; -use sway_ast::{ - expr::LoopControlFlow, token::Delimiter, IfCondition, IfExpr, MatchBranch, MatchBranchKind, -}; -use sway_types::Spanned; +use sway_ast::{expr::LoopControlFlow, IfCondition, IfExpr, MatchBranch, MatchBranchKind}; +use sway_types::{ast::Delimiter, Spanned}; impl Format for IfExpr { fn format( diff --git a/swayfmt/src/utils/language/expr/mod.rs b/swayfmt/src/utils/language/expr/mod.rs index 6e0d51a8a12..bc17b4f3626 100644 --- a/swayfmt/src/utils/language/expr/mod.rs +++ b/swayfmt/src/utils/language/expr/mod.rs @@ -13,10 +13,9 @@ use sway_ast::{ brackets::Parens, keywords::{CommaToken, DotToken}, punctuated::Punctuated, - token::Delimiter, Braces, CodeBlockContents, Expr, ExprStructField, MatchBranch, PathExpr, PathExprSegment, }; -use sway_types::Spanned; +use sway_types::{ast::Delimiter, Spanned}; pub(crate) mod abi_cast; pub(crate) mod asm_block; @@ -36,7 +35,7 @@ impl Format for Expr { formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self { - Self::Error(_) => {} + Self::Error(_, _) => {} Self::Path(path) => path.format(formatted_code, formatter)?, Self::Literal(lit) => lit.format(formatted_code, formatter)?, Self::AbiCast { abi_token, args } => { @@ -742,7 +741,7 @@ impl LeafSpans for Expr { /// Collects various expr field's ByteSpans. fn expr_leaf_spans(expr: &Expr) -> Vec { match expr { - Expr::Error(_) => vec![expr.span().into()], + Expr::Error(_, _) => vec![expr.span().into()], Expr::Path(path) => path.leaf_spans(), Expr::Literal(literal) => literal.leaf_spans(), Expr::AbiCast { abi_token, args } => { diff --git a/swayfmt/src/utils/language/expr/struct_field.rs b/swayfmt/src/utils/language/expr/struct_field.rs index 62ee28eb70e..e9610763151 100644 --- a/swayfmt/src/utils/language/expr/struct_field.rs +++ b/swayfmt/src/utils/language/expr/struct_field.rs @@ -7,8 +7,8 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{token::Delimiter, ExprStructField}; -use sway_types::Spanned; +use sway_ast::ExprStructField; +use sway_types::{ast::Delimiter, Spanned}; impl Format for ExprStructField { fn format( diff --git a/swayfmt/src/utils/language/pattern.rs b/swayfmt/src/utils/language/pattern.rs index dfd9d516220..34c63ef6c5e 100644 --- a/swayfmt/src/utils/language/pattern.rs +++ b/swayfmt/src/utils/language/pattern.rs @@ -11,10 +11,9 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - token::Delimiter, Braces, CommaToken, ExprTupleDescriptor, PathExpr, Pattern, - PatternStructField, Punctuated, + Braces, CommaToken, ExprTupleDescriptor, PathExpr, Pattern, PatternStructField, Punctuated, }; -use sway_types::Spanned; +use sway_types::{ast::Delimiter, Spanned}; impl Format for Pattern { fn format( @@ -317,7 +316,7 @@ impl LeafSpans for Pattern { Pattern::Tuple(tuple) => { collected_spans.append(&mut tuple.leaf_spans()); } - Pattern::Error(spans) => { + Pattern::Error(spans, _) => { let mut leaf_spans = spans.iter().map(|s| ByteSpan::from(s.clone())).collect(); collected_spans.append(&mut leaf_spans) } diff --git a/swayfmt/src/utils/language/punctuated.rs b/swayfmt/src/utils/language/punctuated.rs index 00768e9795e..a4ff42b86ff 100644 --- a/swayfmt/src/utils/language/punctuated.rs +++ b/swayfmt/src/utils/language/punctuated.rs @@ -5,10 +5,9 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - keywords::CommaToken, punctuated::Punctuated, token::PunctKind, ConfigurableField, - StorageField, TypeField, + keywords::CommaToken, punctuated::Punctuated, ConfigurableField, StorageField, TypeField, }; -use sway_types::{Ident, Spanned}; +use sway_types::{ast::PunctKind, Ident, Spanned}; impl Format for Punctuated where diff --git a/swayfmt/src/utils/language/ty.rs b/swayfmt/src/utils/language/ty.rs index 31453ee8849..141efb399d9 100644 --- a/swayfmt/src/utils/language/ty.rs +++ b/swayfmt/src/utils/language/ty.rs @@ -7,10 +7,9 @@ use sway_ast::{ brackets::SquareBrackets, expr::Expr, keywords::{PtrToken, SliceToken, StrToken, Token, UnderscoreToken}, - token::Delimiter, ty::{Ty, TyArrayDescriptor, TyTupleDescriptor}, }; -use sway_types::Spanned; +use sway_types::{ast::Delimiter, Spanned}; impl Format for Ty { fn format( diff --git a/swayfmt/src/utils/mod.rs b/swayfmt/src/utils/mod.rs index e618a518f98..05ec3a01895 100644 --- a/swayfmt/src/utils/mod.rs +++ b/swayfmt/src/utils/mod.rs @@ -1,6 +1,6 @@ use crate::formatter::*; use std::fmt::Write; -use sway_ast::token::PunctKind; +use sway_types::ast::PunctKind; pub(crate) mod language; pub(crate) mod map; 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 10ed4df3eda..00921d33123 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,6 +1,5 @@ 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 88ac3812da1..830c8bf5341 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,8 +1,4 @@ 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.