From 89b92dae9bf8a3d73ff6de1e32860e28d15c1663 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 14 May 2026 11:53:28 +0300 Subject: [PATCH 1/9] add thiserror dependency --- Cargo.lock | 39 ++++++++++++++++++++++++++++++--------- Cargo.toml | 1 + 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bf29fdf..bf6a0fcc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -451,9 +451,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -470,9 +470,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -589,7 +589,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.117", ] [[package]] @@ -651,6 +651,7 @@ dependencies = [ "serde", "serde_json", "simplicity-lang", + "thiserror", ] [[package]] @@ -697,15 +698,35 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.31" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "unicode-ident" version = "1.0.11" @@ -751,7 +772,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -773,7 +794,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.117", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 938f6088..0bdc0e1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ itertools = "0.13.0" arbitrary = { version = "1", optional = true, features = ["derive"] } clap = "4.5.37" chumsky = "0.11.2" +thiserror = "2.0.18" [target.wasm32-unknown-unknown.dependencies] getrandom = { version = "0.2", features = ["js"] } From a764f19b4e8a8d4934fae5482b7f5608927edce4 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 14 May 2026 11:54:22 +0300 Subject: [PATCH 2/9] parse: add error type for parsing stage We moved SyntaxError as a separate struct so we can make custom Display implementation --- src/error.rs | 12 +++++++++ src/parse.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 83420973..609ef963 100644 --- a/src/error.rs +++ b/src/error.rs @@ -634,6 +634,8 @@ pub enum Error { assigned: ResolvedType, }, UseKeywordIsNotSupported, + + ParsingError(crate::parse::Error), } #[rustfmt::skip] @@ -860,6 +862,10 @@ impl fmt::Display for Error { f, "The `use` keyword is not supported yet" ), + Error::ParsingError(err) => write!( + f, + "{err}" + ), } } } @@ -900,6 +906,12 @@ impl From for Error { } } +impl From for Error { + fn from(error: crate::parse::Error) -> Self { + Self::ParsingError(error) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/parse.rs b/src/parse.rs index 42b5dac2..4db7f71c 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -15,11 +15,12 @@ use chumsky::prelude::{ use chumsky::{extra, select, IterParser, Parser}; use either::Either; +use itertools::Itertools; use miniscript::iter::{Tree, TreeLike}; use crate::driver::{CRATE_STR, MAIN_MODULE}; use crate::error::ErrorCollector; -use crate::error::{Error, RichError, Span}; +use crate::error::{RichError, Span}; use crate::impl_eq_hash; use crate::lexer::Token; use crate::num::NonZeroPow2Usize; @@ -31,6 +32,73 @@ use crate::str::{ }; use crate::types::{AliasedType, BuiltinAlias, TypeConstructible, UIntType}; +#[derive(Debug, Clone)] +pub struct SyntaxErrorInfo { + pub expected: Vec, + pub label: Option, + pub found: Option, +} + +impl fmt::Display for SyntaxErrorInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let found_text = self + .found + .clone() + .unwrap_or_else(|| "end of input".to_string()); + + match (&self.label, self.expected.len()) { + (Some(l), _) => write!(f, "Expected {}, found {}", l, found_text), + (None, 1) => { + let exp_text = self.expected.first().unwrap(); + write!(f, "Expected '{}', found '{}'", exp_text, found_text) + } + (None, 0) => write!(f, "Unexpected {}", found_text), + (None, _) => { + let exp_text = self.expected.iter().map(|s| format!("'{}'", s)).join(", "); + write!(f, "Expected one of {}, found '{}'", exp_text, found_text) + } + } + } +} + +impl std::error::Error for SyntaxErrorInfo {} + +#[derive(Debug, Clone, thiserror::Error)] +pub enum Error { + #[error("Grammar error: {msg}")] + Grammar { msg: String }, + + #[error("Cannot parse: {msg}")] + CannotParse { msg: String }, + + #[error( + "Expected a power of two greater than one (2, 4, 8, 16, 32, ...) as list bound, found {bound}" + )] + ListBoundPow2 { bound: usize }, + + #[error(transparent)] + SyntaxError(#[from] SyntaxErrorInfo), + + #[error("Incompatible match arms: {first}, {second}")] + IncompatibleMatchArms { + first: MatchPattern, + second: MatchPattern, + }, + + #[error("Expected a non-negative integer as array size, found {size}")] + ArraySizeNonZero { size: usize }, + + #[error("Type alias `{name}` is already exists as built-in alias")] + RedefinedAliasAsBuiltin { name: AliasName }, +} + +impl Error { + /// Update the error with the affected span. + pub fn with_span(self, span: Span) -> RichError { + RichError::new(self.into(), span) + } +} + /// A program is a sequence of items. #[derive(Clone, Debug)] pub struct Program { @@ -2494,6 +2562,11 @@ mod test { .error() .to_string() .contains("Type alias `Ctx8` is already exists as built-in alias")); + matches!( + ty.error(), + &crate::error::Error::ParsingError(Error::RedefinedAliasAsBuiltin { ref name }) + if name == &AliasName::from_str_unchecked("Ctx8") + ); } #[test] From 763e5f16a326ff96e3ba61999fc094659efe2494 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 14 May 2026 14:17:09 +0300 Subject: [PATCH 3/9] error: change `chumsky` traits implementation to use new error also add inside test reexport for parse::Error so there wouldn't be conflicts after deleteting Error variants --- src/error.rs | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/error.rs b/src/error.rs index 609ef963..75e43464 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,7 @@ use itertools::Itertools; use crate::lexer::Token; use crate::parse::MatchPattern; +use crate::parse::SyntaxErrorInfo; use crate::source::SourceFile; use crate::str::{AliasName, FunctionName, Identifier, JetName, ModuleName, WitnessName}; use crate::types::{ResolvedType, UIntType}; @@ -203,9 +204,9 @@ impl RichError { /// a problem on the parsing side. pub fn parsing_error(reason: &str) -> Self { Self { - error: Box::new(Error::CannotParse { + error: Box::new(Error::ParsingError(crate::parse::Error::CannotParse { msg: reason.to_string(), - }), + })), span: Span::new(0, 0), source: None, } @@ -323,9 +324,8 @@ where { fn merge(self, other: Self) -> Self { match (self.error.as_ref(), other.error.as_ref()) { - (Error::Grammar { .. }, Error::Grammar { .. }) => other, - (Error::Grammar { .. }, _) => other, - (_, Error::Grammar { .. }) => self, + (Error::ParsingError(crate::parse::Error::Grammar { .. }), _) => other, + (_, Error::ParsingError(crate::parse::Error::Grammar { .. })) => self, _ => other, } } @@ -358,11 +358,13 @@ where let found_string = found.map(|t| t.to_string()); Self { - error: Box::new(Error::Syntax { - expected: expected_tokens, - label: None, - found: found_string, - }), + error: Box::new(Error::ParsingError(crate::parse::Error::SyntaxError( + SyntaxErrorInfo { + expected: expected_tokens, + label: None, + found: found_string, + }, + ))), span, source: None, } @@ -385,20 +387,23 @@ where let found_string = found.map(|t| t.to_string()); Self { - error: Box::new(Error::Syntax { - expected: expected_strings, - label: None, - found: found_string, - }), + error: Box::new(Error::ParsingError(crate::parse::Error::SyntaxError( + SyntaxErrorInfo { + expected: expected_strings, + label: None, + found: found_string, + }, + ))), span, source: None, } } fn label_with(&mut self, label: &'tokens str) { - if let Error::Syntax { - label: ref mut l, .. - } = self.error.as_mut() + if let Error::ParsingError(crate::parse::Error::SyntaxError(SyntaxErrorInfo { + label: ref mut l, + .. + })) = self.error.as_mut() { *l = Some(label.to_string()); } @@ -915,6 +920,7 @@ impl From for Error { #[cfg(test)] mod tests { use super::*; + use crate::parse::Error; const CONTENT: &str = r#"let a1: List = None; let x: u32 = Left( From 5efb79bc4b48fdf45bf72f20a044733928b4c1d0 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 14 May 2026 11:58:07 +0300 Subject: [PATCH 4/9] ast: add error type for AST This also made change inside some modules to use ast::Error instead of error::Error. --- src/ast.rs | 125 +++++++++++++++++++++++++++++++++++++++++++++++-- src/error.rs | 14 ++++++ src/pattern.rs | 2 +- src/value.rs | 3 +- src/witness.rs | 7 +-- 5 files changed, 141 insertions(+), 10 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index fca0947f..4947a45a 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -9,12 +9,12 @@ use simplicity::jet::{Elements, Jet}; use crate::debug::{CallTracker, DebugSymbols, TrackedCallName}; use crate::driver::{FileScoped, SymbolTable, MAIN_MODULE, MAIN_STR}; -use crate::error::{Error, RichError, Span, WithSpan}; +use crate::error::{RichError, Span, WithSpan}; use crate::jet::JetHL; use crate::num::{NonZeroPow2Usize, Pow2Usize}; use crate::parse::MatchPattern; use crate::pattern::Pattern; -use crate::str::{AliasName, FunctionName, Identifier, ModuleName, WitnessName}; +use crate::str::{AliasName, FunctionName, Identifier, JetName, ModuleName, WitnessName}; use crate::types::{ AliasedType, ResolvedType, StructuralType, TypeConstructible, TypeDeconstructible, UIntType, }; @@ -22,6 +22,121 @@ use crate::value::{UIntValue, Value}; use crate::witness::{Parameters, WitnessTypes}; use crate::{driver, impl_eq_hash, parse}; +#[derive(Debug, thiserror::Error, Clone)] +pub enum Error { + #[error("Main function is required")] + MainRequired, + + #[error("Function `{name}` was defined multiple times")] + FunctionRedefined { name: FunctionName }, + + #[error("Type alias `{name}` is not defined")] + UndefinedAlias { name: AliasName }, + + #[error("INTERNAL ERROR: {msg}")] + Internal { msg: String }, + + #[error("Item `{name}` is private")] + PrivateItem { name: String }, + + #[error("Type alias `{name}` was defined multiple times")] + RedefinedAlias { name: AliasName }, + + #[error("Expected expression of type `{expected}`, found type `{found}`")] + ExpressionTypeMismatch { + expected: ResolvedType, + found: ResolvedType, + }, + + #[error("Witness expressions are not allowed outside the `main` function")] + WitnessOutsideMain, + + #[error("Witness `{name}` has been used before somewhere in the program")] + WitnessReused { name: WitnessName }, + + #[error("Function `{name}` was called but not defined")] + FunctionUndefined { name: FunctionName }, + + #[error("Failed to compile to Simplicity: {msg}")] + CannotCompile { msg: String }, + + #[error("Main function takes no input parameters")] + MainNoInputs, + + #[error("Main function produces no output")] + MainNoOutput, + + #[error("The 'main' function must be defined in the entry point file")] + MainOutOfEntryFile, + + #[error("Expected expression of type `{ty}`; found something else")] + ExpressionUnexpectedType { ty: ResolvedType }, + + #[error("Variable `{identifier}` is used twice in the pattern")] + VariableReuseInPattern { identifier: Identifier }, + + #[error("Variable `{identifier}` is not defined")] + UndefinedVariable { identifier: Identifier }, + + #[error("Value is out of bounds for type `{ty}`")] + IntegerOutOfBounds { ty: UIntType }, + + #[error("Expected {expected} arguments, found {found} arguments")] + InvalidNumberOfArguments { expected: usize, found: usize }, + + #[error("Cannot cast values of type `{source_type}` as values of type `{target_type}`")] + InvalidCast { + source_type: ResolvedType, + target_type: ResolvedType, + }, + + #[error("Jet `{name}` does not exist")] + JetDoesNotExist { name: JetName }, + + #[error("Expected a signature like `fn {name}(element: E, accumulator: A) -> A` for a fold")] + FunctionNotFoldable { name: FunctionName }, + + #[error("Module `{0}` is defined twice")] + ModuleRedefined(ModuleName), + + #[error("Witness `{0}` has already been assigned a value")] + WitnessReassigned(WitnessName), + + #[error("Expected a signature like `fn {name}(accumulator: A, context: C, counter u{{1,2,4,8,16}}) -> Either` for a for-while loop")] + FunctionNotLoopable { name: FunctionName }, + + #[error("Witness `{name}` was declared with type `{declared}` but its assigned value is of type `{assigned}`")] + WitnessTypeMismatch { + name: WitnessName, + declared: ResolvedType, + assigned: ResolvedType, + }, + + #[error("Parameter `{name}` is missing an argument")] + ArgumentMissing { name: WitnessName }, + + #[error( + "Parameter `{name}` was declared with type `{declared}` but its assigned argument is of type `{assigned}`" + )] + ArgumentTypeMismatch { + name: WitnessName, + declared: ResolvedType, + assigned: ResolvedType, + }, + + #[error("The `use` keyword is not supported yet")] + UseKeywordIsNotSupported, + + #[error("Integer parsing error")] + ParseIntCrate(#[from] crate::num::ParseIntError), + + #[error("Integer parsing error")] + ParseInt(#[from] std::num::ParseIntError), + + #[error("Expected a valid bit string length (1, 2, 4, 8, 16, 32, 64, 128, 256), found {len}")] + BitStringPow2 { len: usize }, +} + /// A program consists of the main function. /// /// Other items such as custom functions or type aliases @@ -981,7 +1096,7 @@ impl AbstractSyntaxTree for Item { Function::analyze(function, ty, scope).map(Self::Function) } parse::Item::Use(use_decl) => Err(RichError::new( - Error::UseKeywordIsNotSupported, + crate::error::Error::AnalyzingError(Error::UseKeywordIsNotSupported), *use_decl.span(), )), parse::Item::Module => Ok(Self::Module), @@ -1428,8 +1543,8 @@ impl AbstractSyntaxTree for Call { CallName::TypeCast(source) => { if StructuralType::from(&source) != StructuralType::from(ty) { return Err(Error::InvalidCast { - source, - target: ty.clone(), + source_type: source, + target_type: ty.clone(), }) .with_span(from); } diff --git a/src/error.rs b/src/error.rs index 75e43464..15a6976e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -641,6 +641,7 @@ pub enum Error { UseKeywordIsNotSupported, ParsingError(crate::parse::Error), + AnalyzingError(crate::ast::Error), } #[rustfmt::skip] @@ -871,6 +872,10 @@ impl fmt::Display for Error { f, "{err}" ), + Error::AnalyzingError(err) => write!( + f, + "{err}" + ), } } } @@ -917,6 +922,15 @@ impl From for Error { } } +impl From for Error { + fn from(error: crate::ast::Error) -> Self { + match error { + crate::ast::Error::Internal { msg } => Self::Internal { msg }, + _ => Self::AnalyzingError(error), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/pattern.rs b/src/pattern.rs index b54726ad..f26c355e 100644 --- a/src/pattern.rs +++ b/src/pattern.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use miniscript::iter::{Tree, TreeLike}; use crate::array::BTreeSlice; -use crate::error::Error; +use crate::ast::Error; use crate::named::{CoreExt, PairBuilder, SelectorBuilder}; use crate::str::Identifier; use crate::types::{ResolvedType, TypeInner}; diff --git a/src/value.rs b/src/value.rs index 1ccb38bd..75172d99 100644 --- a/src/value.rs +++ b/src/value.rs @@ -8,7 +8,8 @@ use simplicity::types::Final as SimType; use simplicity::{BitCollector, Value as SimValue, ValueRef}; use crate::array::{BTreeSlice, Combiner, Partition, Unfolder}; -use crate::error::{Error, RichError, WithSpan}; +use crate::ast::Error; +use crate::error::{RichError, WithSpan}; use crate::num::{NonZeroPow2Usize, Pow2Usize, U256}; use crate::parse::ParseFromStr; use crate::str::{Binary, Decimal, Hexadecimal}; diff --git a/src/witness.rs b/src/witness.rs index 3fd878d4..218095cd 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use std::fmt; use std::sync::Arc; -use crate::error::{Error, RichError, WithContent, WithSpan}; +use crate::ast::Error; +use crate::error::{RichError, WithContent, WithSpan}; use crate::parse::ParseFromStr; use crate::str::WitnessName; use crate::types::{AliasedType, ResolvedType}; @@ -234,10 +235,10 @@ mod tests { ) .expect("driver works"); match ast::Program::analyze(&driver_program, Box::new(ElementsJetHinter::new())) - .map_err(Error::from) + .map_err(crate::error::Error::from) { Ok(_) => panic!("Witness reuse was falsely accepted"), - Err(Error::WitnessReused { .. }) => {} + Err(crate::error::Error::AnalyzingError(ast::Error::WitnessReused { .. })) => {} Err(error) => panic!("Unexpected error: {error}"), } } From 34a1b2d3c6603a319d337736c5ce5ac3999c0e00 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 28 May 2026 16:34:11 +0300 Subject: [PATCH 5/9] driver: change RichError::new to Error.with_span This changes driver functions to use WithSpan trait --- src/driver/resolve_order.rs | 62 ++++++++++++++----------------------- src/resolution.rs | 55 +++++++++++++------------------- 2 files changed, 45 insertions(+), 72 deletions(-) diff --git a/src/driver/resolve_order.rs b/src/driver/resolve_order.rs index ad5463d5..e28c88a9 100644 --- a/src/driver/resolve_order.rs +++ b/src/driver/resolve_order.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use crate::driver::{DependencyGraph, MAIN_MODULE, MAIN_STR}; use crate::error::{Error, ErrorCollector, RichError, Span}; +use crate::error::WithSpan; use crate::impl_eq_hash; use crate::parse::{self, AliasedSymbolName, Function, TypeAlias, Visibility}; use crate::str::{AliasName, FunctionName, SymbolName}; @@ -320,26 +321,19 @@ impl DependencyGraph { let orig_id = (target_name.clone(), ind); // 2. Verify Existence using T - let visibility: &Visibility = - namespace.resolutions[ind] - .get(&target_name) - .ok_or_else(|| { - RichError::new( - Error::UnresolvedItem { - name: name.to_string(), - }, - span, - ) - })?; + let visibility: &Visibility = namespace.resolutions[ind] + .get(&target_name) + .ok_or_else(|| Error::UnresolvedItem { + name: name.to_string(), + }) + .with_span(span)?; // 3. Verify Visibility if matches!(visibility, parse::Visibility::Private) { - return Err(RichError::new( - Error::PrivateItem { - name: name.to_string(), - }, - span, - )); + return Err(Error::PrivateItem { + name: name.to_string(), + }) + .with_span(span); } // 4. Determine the local name and ID up front @@ -351,7 +345,7 @@ impl DependencyGraph { let t_alias: T = alias_sym.clone().into(); if t_alias.to_string() == MAIN_STR { - return Err(RichError::new(Error::MainCannotBeAlias, span)); + return Err(Error::MainCannotBeAlias).with_span(span); } t_alias } else { @@ -362,21 +356,17 @@ impl DependencyGraph { // 5. Check for collisions using `namespace` fields if namespace.registry.direct_targets.contains_key(&local_id) { - return Err(RichError::new( - Error::DuplicateAlias { - name: local_symbol.to_string(), - }, - span, - )); + return Err(Error::DuplicateAlias { + name: local_symbol.to_string(), + }) + .with_span(span); } if namespace.memo.contains(&local_id) { - return Err(RichError::new( - Error::RedefinedItem { - name: local_symbol.to_string(), - }, - span, - )); + return Err(Error::RedefinedItem { + name: local_symbol.to_string(), + }) + .with_span(span); } namespace.memo.insert(local_id.clone()); @@ -421,10 +411,7 @@ fn register_type_alias( let local_id = (name.clone(), source_id); if tracker.memo.contains(&local_id) { - return Err(RichError::new( - Error::RedefinedAlias { name: name.clone() }, - *item.span(), - )); + return Err(Error::RedefinedAlias { name: name.clone() }).with_span(*item.span()); } tracker.memo.insert(local_id); @@ -443,14 +430,11 @@ fn register_function( let local_id = (name.clone(), source_id); if name.as_inner() == MAIN_STR && matches!(item.visibility(), Visibility::Public) { - return Err(RichError::new(Error::MainCannotBePublic, *item.span())); + return Err(Error::MainCannotBePublic).with_span(*item.span()); } if tracker.memo.contains(&local_id) { - return Err(RichError::new( - Error::FunctionRedefined { name: name.clone() }, - *item.span(), - )); + return Err(Error::FunctionRedefined { name: name.clone() }).with_span(*item.span()); } tracker.memo.insert(local_id); diff --git a/src/resolution.rs b/src/resolution.rs index eea71223..3091b455 100644 --- a/src/resolution.rs +++ b/src/resolution.rs @@ -224,25 +224,19 @@ impl DependencyMap { ) -> Result { let drp_name = use_decl.drp_name()?; - let resolved = - Self::build_and_verify_path(&remapping.target, &parts[1..]).map_err(|failed_path| { - RichError::new( - Error::ExternalFileNotFound { - lib: drp_name.to_string(), - filename: failed_path, - }, - *use_decl.span(), - ) - })?; + let resolved = Self::build_and_verify_path(&remapping.target, &parts[1..]) + .map_err(|failed_path| Error::ExternalFileNotFound { + lib: drp_name.to_string(), + filename: failed_path, + }) + .with_span(*use_decl.span())?; if !resolved.starts_with(&remapping.target) { - return Err(RichError::new( - Error::ExternalFileNotFound { - lib: drp_name.to_string(), - filename: resolved.as_path().to_path_buf(), - }, - *use_decl.span(), - )); + return Err(Error::ExternalFileNotFound { + lib: drp_name.to_string(), + filename: resolved.as_path().to_path_buf(), + }) + .with_span(*use_decl.span()); } self.check_local_file_imported_as_external(current_file, &resolved, use_decl)?; @@ -262,24 +256,19 @@ impl DependencyMap { .ok_or_else(|| Error::Internal { msg: "The 'crate' root path was not configured by the compiler.".to_string(), }) - .map_err(|e| RichError::new(e, *use_decl.span()))?; - - let resolved = Self::build_and_verify_path(root, &parts[1..]).map_err(|failed_path| { - RichError::new( - Error::FileNotFound { - filename: failed_path, - }, - *use_decl.span(), - ) - })?; + .with_span(*use_decl.span())?; + + let resolved = Self::build_and_verify_path(root, &parts[1..]) + .map_err(|failed_path| Error::FileNotFound { + filename: failed_path, + }) + .with_span(*use_decl.span())?; if !resolved.starts_with(root) { - return Err(RichError::new( - Error::FileNotFound { - filename: resolved.as_path().to_path_buf(), - }, - *use_decl.span(), - )); + return Err(Error::FileNotFound { + filename: resolved.as_path().to_path_buf(), + }) + .with_span(*use_decl.span()); } Ok(resolved) From 2a3d0826c6ab5917973682c1a9206f4a8b20f56e Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 28 May 2026 16:34:49 +0300 Subject: [PATCH 6/9] driver: add error type for driver and resolution steps --- src/driver/error.rs | 65 +++++++++++++++++++++++++++++++++++++ src/driver/mod.rs | 8 +++-- src/driver/resolve_order.rs | 16 ++++++--- src/error.rs | 14 ++++++++ src/resolution.rs | 11 ++++--- 5 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 src/driver/error.rs diff --git a/src/driver/error.rs b/src/driver/error.rs new file mode 100644 index 00000000..4a0a35ff --- /dev/null +++ b/src/driver/error.rs @@ -0,0 +1,65 @@ +use std::path::PathBuf; + +use crate::str::{AliasName, FunctionName}; + +#[derive(Debug, thiserror::Error, Clone, Eq, PartialEq, Hash)] +pub enum Error { + #[error("Item `{name}` could not be found")] + UnresolvedItem { name: String }, + + #[error("Item `{name}` is private")] + PrivateItem { name: String }, + + #[error("The alias `{name}` was defined multiple times")] + DuplicateAlias { name: String }, + + #[error("Item `{name}` was defined multiple times")] + RedefinedItem { name: String }, + + #[error("Main function cannot be public")] + MainCannotBePublic, + + #[error("Function `{name}` was defined multiple times")] + FunctionRedefined { name: FunctionName }, + + #[error("Unknown module or library '{name}'")] + UnknownLibrary { name: String }, + + #[error("Main function cannot be alias")] + MainCannotBeAlias, + + #[error("Type alias `{name}` was defined multiple times")] + RedefinedAlias { name: AliasName }, + + #[error("Local file `{}` not found", filename.display())] + FileNotFound { filename: PathBuf }, + + #[error( + "File `{}` is part of the local project and must be imported using the `crate::` prefix", path.to_string_lossy() + + )] + LocalFileImportedAsExternal { path: PathBuf }, + + #[error("File `{}` not found in external library `{}`", lib, filename.display())] + ExternalFileNotFound { lib: String, filename: PathBuf }, + + #[error("INTERNAL ERROR: {msg}")] + Internal { msg: String }, + + #[error("Path not found: {}", path.display())] + DependencyPathNotFound { path: PathBuf }, + + #[error("Path must be a directory: {}", path.display())] + DependencyNotADirectory { path: PathBuf }, + + #[error("The '{keyword}' keyword is reserved and cannot be manually mapped. Use the builder's context definitions instead.")] + ReservedDependencyKeyword { keyword: String }, + + #[error("Duplicate dependency mapping: alias '{alias}' is defined multiple times for context '{context}'")] + DuplicateDependencyAlias { alias: String, context: String }, + + #[error( + "Invalid dependency alias '{alias}': must be a valid identifier and not a reserved keyword" + )] + InvalidDependencyIdentifier { alias: String }, +} diff --git a/src/driver/mod.rs b/src/driver/mod.rs index 0f026f84..e2487942 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -27,6 +27,7 @@ //! resolves and parses these external files relative to the entry point during //! the dependency graph construction. +mod error; mod linearization; pub(crate) mod resolve_order; @@ -36,13 +37,15 @@ use std::sync::Arc; use chumsky::container::Container; -use crate::error::{Error, ErrorCollector, RichError, Span}; +use crate::error::{ErrorCollector, RichError, Span}; use crate::parse::{self, ParseFromStrWithErrors}; use crate::resolution::DependencyMap; use crate::source::{CanonPath, CanonSourceFile}; pub use crate::driver::resolve_order::{FileScoped, Program, SymbolTable}; +pub use crate::driver::error::Error; + /// The reserved identifier for the program's entry point. pub(crate) const MAIN_STR: &str = "main"; @@ -209,7 +212,8 @@ impl DependencyGraph { let err = RichError::new( Error::FileNotFound { filename: PathBuf::from(path.as_path()), - }, + } + .into(), span, ) .with_source(importer_source.clone()); diff --git a/src/driver/resolve_order.rs b/src/driver/resolve_order.rs index e28c88a9..6b1f8ac0 100644 --- a/src/driver/resolve_order.rs +++ b/src/driver/resolve_order.rs @@ -1,9 +1,10 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::sync::Arc; +use crate::driver::error::Error; use crate::driver::{DependencyGraph, MAIN_MODULE, MAIN_STR}; -use crate::error::{Error, ErrorCollector, RichError, Span}; use crate::error::WithSpan; +use crate::error::{ErrorCollector, RichError, Span}; use crate::impl_eq_hash; use crate::parse::{self, AliasedSymbolName, Function, TypeAlias, Visibility}; use crate::str::{AliasName, FunctionName, SymbolName}; @@ -45,7 +46,8 @@ impl Program { RichError::new( Error::UnknownLibrary { name: use_decl.str_path(), - }, + } + .into(), *use_decl.span(), ) .with_content(content.clone()), @@ -265,8 +267,14 @@ impl DependencyGraph { (Ok(()), _) | (_, Ok(())) => Ok(()), (Err(err_alias), Err(err_func)) => { - let alias_is_missing = matches!(err_alias.error(), Error::UnresolvedItem { .. }); - let func_is_missing = matches!(err_func.error(), Error::UnresolvedItem { .. }); + let alias_is_missing = matches!( + err_alias.error(), + crate::error::Error::DriverError(Error::UnresolvedItem { .. }) + ); + let func_is_missing = matches!( + err_func.error(), + crate::error::Error::DriverError(Error::UnresolvedItem { .. }) + ); if !alias_is_missing || func_is_missing { // If it's missing everywhere, OR if the function is missing diff --git a/src/error.rs b/src/error.rs index 15a6976e..2a5b6349 100644 --- a/src/error.rs +++ b/src/error.rs @@ -642,6 +642,7 @@ pub enum Error { ParsingError(crate::parse::Error), AnalyzingError(crate::ast::Error), + DriverError(crate::driver::Error), } #[rustfmt::skip] @@ -876,6 +877,10 @@ impl fmt::Display for Error { f, "{err}" ), + Error::DriverError(err) => write!( + f, + "{err}" + ), } } } @@ -931,6 +936,15 @@ impl From for Error { } } +impl From for Error { + fn from(error: crate::driver::Error) -> Self { + match error { + crate::driver::Error::Internal { msg } => Self::Internal { msg }, + _ => Self::DriverError(error), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/resolution.rs b/src/resolution.rs index 3091b455..67695271 100644 --- a/src/resolution.rs +++ b/src/resolution.rs @@ -1,5 +1,5 @@ -use crate::driver::CRATE_STR; -use crate::error::{Error, RichError, WithSpan as _}; +use crate::driver::{Error, CRATE_STR}; +use crate::error::{RichError, WithSpan}; use crate::parse::UseDecl; use crate::source::CanonPath; @@ -404,7 +404,7 @@ pub(crate) mod tests { assert!(result.is_err()); assert!(matches!( result.unwrap_err().error(), - Error::UnknownLibrary { .. } + crate::error::Error::DriverError(Error::UnknownLibrary { .. }) )); } @@ -462,7 +462,7 @@ pub(crate) mod tests { assert!(matches!( result.unwrap_err().error(), - Error::LocalFileImportedAsExternal { .. } + crate::error::Error::DriverError(Error::LocalFileImportedAsExternal { .. }) )); } @@ -503,7 +503,8 @@ pub(crate) mod tests { assert!(result.is_err()); assert!(matches!( result.unwrap_err().error(), - Error::Internal{msg} if msg.contains("The 'crate' root path was not configured") + crate::error::Error::Internal{ msg } + if msg.contains("The 'crate' root path was not configured") )); } From 8a03d6846c8caa9d6fdbeeda4d2db0675e520461 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 14 May 2026 12:59:53 +0300 Subject: [PATCH 7/9] compile: add compiling error --- src/compile/error.rs | 8 ++++++++ src/compile/mod.rs | 5 ++++- src/error.rs | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/compile/error.rs diff --git a/src/compile/error.rs b/src/compile/error.rs new file mode 100644 index 00000000..b89703f1 --- /dev/null +++ b/src/compile/error.rs @@ -0,0 +1,8 @@ +#[derive(Debug, thiserror::Error, Clone)] +pub enum Error { + #[error("Variable `{identifier}` is not defined")] + UndefinedVariable { identifier: crate::str::Identifier }, + + #[error("Simplicity type error")] + TypeError(#[from] simplicity::types::Error), +} diff --git a/src/compile/mod.rs b/src/compile/mod.rs index ad3a44a8..6a987010 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -1,6 +1,9 @@ //! Compile the parsed ast into a simplicity program mod builtins; +mod error; + +pub use error::Error; use std::sync::Arc; @@ -15,7 +18,7 @@ use crate::ast::{ SingleExpressionInner, Statement, }; use crate::debug::CallTracker; -use crate::error::{Error, RichError, Span, WithSpan}; +use crate::error::{RichError, Span, WithSpan}; use crate::named::{self, CoreExt, PairBuilder}; use crate::num::{NonZeroPow2Usize, Pow2Usize}; use crate::pattern::{BasePattern, Pattern}; diff --git a/src/error.rs b/src/error.rs index 2a5b6349..8da6d7e2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -643,6 +643,7 @@ pub enum Error { ParsingError(crate::parse::Error), AnalyzingError(crate::ast::Error), DriverError(crate::driver::Error), + CompileError(crate::compile::Error), } #[rustfmt::skip] @@ -881,6 +882,10 @@ impl fmt::Display for Error { f, "{err}" ), + Error::CompileError(err) => write!( + f, + "{err}" + ), } } } @@ -945,6 +950,12 @@ impl From for Error { } } +impl From for Error { + fn from(error: crate::compile::Error) -> Self { + Self::CompileError(error) + } +} + #[cfg(test)] mod tests { use super::*; From 5675aff84dba7a3a1d9b3d73daee1f62026c2ea9 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Thu, 14 May 2026 13:59:02 +0300 Subject: [PATCH 8/9] lexer: add LexerError in error::Error --- src/error.rs | 7 +++++++ src/lexer.rs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 8da6d7e2..1205bb79 100644 --- a/src/error.rs +++ b/src/error.rs @@ -640,6 +640,9 @@ pub enum Error { }, UseKeywordIsNotSupported, + LexerError { + msg: String, + }, ParsingError(crate::parse::Error), AnalyzingError(crate::ast::Error), DriverError(crate::driver::Error), @@ -886,6 +889,10 @@ impl fmt::Display for Error { f, "{err}" ), + Error::LexerError{msg} => write!( + f, + "{msg}" + ), } } } diff --git a/src/lexer.rs b/src/lexer.rs index 06d63adc..229662de 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -247,7 +247,7 @@ pub fn lex<'src>(input: &'src str) -> (Option>, Vec Date: Thu, 14 May 2026 14:02:21 +0300 Subject: [PATCH 9/9] remove old Error variants --- src/error.rs | 412 ++------------------------------------------------- 1 file changed, 9 insertions(+), 403 deletions(-) diff --git a/src/error.rs b/src/error.rs index 1205bb79..913134d7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,5 @@ use std::fmt; use std::ops::Range; -use std::path::PathBuf; use std::sync::Arc; use chumsky::error::Error as ChumskyError; @@ -10,14 +9,9 @@ use chumsky::text::Char; use chumsky::util::MaybeRef; use chumsky::DefaultExpected; -use itertools::Itertools; - use crate::lexer::Token; -use crate::parse::MatchPattern; use crate::parse::SyntaxErrorInfo; use crate::source::SourceFile; -use crate::str::{AliasName, FunctionName, Identifier, JetName, ModuleName, WitnessName}; -use crate::types::{ResolvedType, UIntType}; /// Area that an object spans inside a file. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -480,169 +474,8 @@ impl fmt::Display for ErrorCollector { /// Records _what_ happened but not where. #[derive(Debug, Clone)] pub enum Error { - DependencyPathNotFound { - path: PathBuf, - }, - DependencyNotADirectory { - path: PathBuf, - }, - ReservedDependencyKeyword { - keyword: String, - }, - DuplicateDependencyAlias { - alias: String, - context: String, - }, - InvalidDependencyIdentifier { - alias: String, - }, - Internal { - msg: String, - }, - UnknownLibrary { - name: String, - }, - ArraySizeNonZero { - size: usize, - }, - ListBoundPow2 { - bound: usize, - }, - BitStringPow2 { - len: usize, - }, - CannotParse { - msg: String, - }, - Grammar { - msg: String, - }, - Syntax { - expected: Vec, - label: Option, - found: Option, - }, - IncompatibleMatchArms { - first: MatchPattern, - second: MatchPattern, - }, - // TODO: Remove CompileError once SimplicityHL has a type system - // The SimplicityHL compiler should never produce ill-typed Simplicity code - // The compiler can only be this precise if it knows a type system at least as expressive as Simplicity's - CannotCompile { - source: simplicity::types::Error, - }, - ParseInt { - source: std::num::ParseIntError, - }, - ParseCrateInt { - source: crate::num::ParseIntError, - }, - JetDoesNotExist { - name: JetName, - }, - InvalidCast { - source: ResolvedType, - target: ResolvedType, - }, - FileNotFound { - filename: PathBuf, - }, - ExternalFileNotFound { - lib: String, - filename: PathBuf, - }, - LocalFileImportedAsExternal { - path: PathBuf, - }, - RedefinedItem { - name: String, - }, - UnresolvedItem { - name: String, - }, - PrivateItem { - name: String, - }, - MainNoInputs, - MainNoOutput, - MainRequired, - MainOutOfEntryFile, - MainCannotBePublic, - MainCannotBeAlias, - FunctionRedefined { - name: FunctionName, - }, - FunctionUndefined { - name: FunctionName, - }, - InvalidNumberOfArguments { - expected: usize, - found: usize, - }, - FunctionNotFoldable { - name: FunctionName, - }, - FunctionNotLoopable { - name: FunctionName, - }, - ExpressionUnexpectedType { - ty: ResolvedType, - }, - ExpressionTypeMismatch { - expected: ResolvedType, - found: ResolvedType, - }, - ExpressionNotConstant, - IntegerOutOfBounds { - ty: UIntType, - }, - UndefinedVariable { - identifier: Identifier, - }, - RedefinedAlias { - name: AliasName, - }, - RedefinedAliasAsBuiltin { - name: AliasName, - }, - UndefinedAlias { - name: AliasName, - }, - DuplicateAlias { - name: String, - }, - VariableReuseInPattern { - identifier: Identifier, - }, - WitnessReused { - name: WitnessName, - }, - WitnessTypeMismatch { - name: WitnessName, - declared: ResolvedType, - assigned: ResolvedType, - }, - WitnessReassigned { - name: WitnessName, - }, - WitnessOutsideMain, - ModuleRedefined { - name: ModuleName, - }, - ArgumentMissing { - name: WitnessName, - }, - ArgumentTypeMismatch { - name: WitnessName, - declared: ResolvedType, - assigned: ResolvedType, - }, - UseKeywordIsNotSupported, - - LexerError { - msg: String, - }, + Internal { msg: String }, + LexerError { msg: String }, ParsingError(crate::parse::Error), AnalyzingError(crate::ast::Error), DriverError(crate::driver::Error), @@ -653,225 +486,9 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Error::DependencyPathNotFound { path } => write!( - f, - "Path not found: {}", path.display() - ), - Error::DependencyNotADirectory { path } => write!( - f, - "Path must be a directory: {}", path.display() - ), - Error::ReservedDependencyKeyword { keyword } => write!( - f, - "The '{keyword}' keyword is reserved and cannot be manually mapped. Use the builder's context definitions instead." - ), - Error::DuplicateDependencyAlias { alias, context } => write!( - f, - "Duplicate dependency mapping: alias '{alias}' is defined multiple times for context '{context}'" - ), - Error::InvalidDependencyIdentifier { alias } => write!( - f, - "Invalid dependency alias '{alias}': must be a valid identifier and not a reserved keyword" - ), Error::Internal { msg } => write!( f, - "INTERNAL ERROR: {msg}" - ), - Error::UnknownLibrary { name } => write!( - f, - "Unknown module or library '{name}'" - ), - Error::ArraySizeNonZero { size } => write!( - f, - "Expected a non-negative integer as array size, found {size}" - ), - Error::ListBoundPow2 { bound } => write!( - f, - "Expected a power of two greater than one (2, 4, 8, 16, 32, ...) as list bound, found {bound}" - ), - Error::BitStringPow2 { len } => write!( - f, - "Expected a valid bit string length (1, 2, 4, 8, 16, 32, 64, 128, 256), found {len}" - ), - Error::CannotParse{ msg } => write!( - f, - "Cannot parse: {msg}" - ), - Error::Grammar{ msg } => write!( - f, - "Grammar error: {msg}" - ), - Error::FileNotFound { filename: path } => write!( - f, - "Local file `{}` not found", path.to_string_lossy() - ), - Error::ExternalFileNotFound { lib, filename: path } => write!( - f, - "File `{}` not found in external library `{}`", path.to_string_lossy(), lib - ), - Error::LocalFileImportedAsExternal { path } => write!( - f, - "File `{}` is part of the local project and must be imported using the `crate::` prefix", path.to_string_lossy() - ), - Error::Syntax { expected, label, found } => { - let found_text = found.clone().unwrap_or("end of input".to_string()); - match (label, expected.len()) { - (Some(l), _) => write!(f, "Expected {}, found {}", l, found_text), - (None, 1) => { - let exp_text = expected.first().unwrap(); - write!(f, "Expected '{}', found '{}'", exp_text, found_text) - } - (None, 0) => write!(f, "Unexpected {}", found_text), - (None, _) => { - let exp_text = expected.iter().map(|s| format!("'{}'", s)).join(", "); - write!(f, "Expected one of {}, found '{}'", exp_text, found_text) - } - } - } - Error::IncompatibleMatchArms { first, second} => write!( - f, - "Match arm `{first}` is incompatible with arm `{second}`" - ), - Error::CannotCompile{ .. } => write!( - f, - "Failed to compile to Simplicity" - ), - Error::ParseInt { .. } | Error::ParseCrateInt { .. } => write!(f, "Integer parsing error"), - Error::JetDoesNotExist { name } => write!( - f, - "Jet `{name}` does not exist" - ), - Error::InvalidCast { source, target } => write!( - f, - "Cannot cast values of type `{source}` as values of type `{target}`" - ), - Error::MainNoInputs => write!( - f, - "Main function takes no input parameters" - ), - Error::MainNoOutput => write!( - f, - "Main function produces no output" - ), - Error::MainRequired => write!( - f, - "Main function is required" - ), - Error::MainOutOfEntryFile => write!( - f, - "The 'main' function must be defined in the entry point file" - ), - Error::MainCannotBePublic => write!( - f, - "Main function cannot be public" - ), - Error::MainCannotBeAlias => write!( - f, - "Main function cannot be alias", - ), - Error::FunctionRedefined { name } => write!( - f, - "Function `{name}` was defined multiple times" - ), - Error::FunctionUndefined { name } => write!( - f, - "Function `{name}` was called but not defined" - ), - Error::RedefinedItem { name } => write!( - f, - "Item `{name}` was defined multiple times" - ), - Error::UnresolvedItem { name } => write!( - f, - "Item `{name}` could not be found" - ), - Error::PrivateItem { name } => write!( - f, - "Item `{name}` is private" - ), - Error::InvalidNumberOfArguments { expected, found } => write!( - f, - "Expected {expected} arguments, found {found} arguments" - ), - Error::FunctionNotFoldable { name } => write!( - f, - "Expected a signature like `fn {name}(element: E, accumulator: A) -> A` for a fold" - ), - Error::FunctionNotLoopable { name } => write!( - f, - "Expected a signature like `fn {name}(accumulator: A, context: C, counter u{{1,2,4,8,16}}) -> Either` for a for-while loop" - ), - Error::ExpressionUnexpectedType { ty } => write!( - f, - "Expected expression of type `{ty}`; found something else" - ), - Error::ExpressionTypeMismatch { expected, found } => write!( - f, - "Expected expression of type `{expected}`, found type `{found}`" - ), - Error::ExpressionNotConstant => write!( - f, - "Expression cannot be evaluated at compile time" - ), - Error::IntegerOutOfBounds { ty } => write!( - f, - "Value is out of bounds for type `{ty}`" - ), - Error::UndefinedVariable { identifier } => write!( - f, - "Variable `{identifier}` is not defined" - ), - Error::RedefinedAlias { name } => write!( - f, - "Type alias `{name}` was defined multiple times" - ), - Error::RedefinedAliasAsBuiltin { name } => write!( - f, - "Type alias `{name}` is already exists as built-in alias" - ), - Error::UndefinedAlias { name } => write!( - f, - "Type alias `{name}` is not defined" - ), - Error::DuplicateAlias { name } => write!( - f, - "The alias `{name}` was defined multiple times" - ), - Error::VariableReuseInPattern { identifier } => write!( - f, - "Variable `{identifier}` is used twice in the pattern" - ), - Error::WitnessReused { name } => write!( - f, - "Witness `{name}` has been used before somewhere in the program" - ), - Error::WitnessTypeMismatch { name, declared, assigned } => write!( - f, - "Witness `{name}` was declared with type `{declared}` but its assigned value is of type `{assigned}`" - ), - Error::WitnessReassigned { name } => write!( - f, - "Witness `{name}` has already been assigned a value" - ), - Error::WitnessOutsideMain => write!( - f, - "Witness expressions are not allowed outside the `main` function" - ), - Error::ModuleRedefined { name } => write!( - f, - "Module `{name}` is defined twice" - ), - Error::ArgumentMissing { name } => write!( - f, - "Parameter `{name}` is missing an argument" - ), - Error::ArgumentTypeMismatch { name, declared, assigned } => write!( - f, - "Parameter `{name}` was declared with type `{declared}` but its assigned argument is of type `{assigned}`" - ), - Error::UseKeywordIsNotSupported => write!( - f, - "The `use` keyword is not supported yet" + "{msg}" ), Error::ParsingError(err) => write!( f, @@ -889,7 +506,7 @@ impl fmt::Display for Error { f, "{err}" ), - Error::LexerError{msg} => write!( + Error::LexerError { msg } => write!( f, "{msg}" ), @@ -900,9 +517,10 @@ impl fmt::Display for Error { impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { - Error::ParseInt { source } => Some(source), - Error::ParseCrateInt { source } => Some(source), - Error::CannotCompile { source } => Some(source), + Error::ParsingError(err) => Some(err), + Error::AnalyzingError(err) => Some(err), + Error::DriverError(err) => Some(err), + Error::CompileError(err) => Some(err), _ => None, } } @@ -915,21 +533,9 @@ impl Error { } } -impl From for Error { - fn from(error: std::num::ParseIntError) -> Self { - Self::ParseInt { source: error } - } -} - -impl From for Error { - fn from(error: crate::num::ParseIntError) -> Self { - Self::ParseCrateInt { source: error } - } -} - impl From for Error { fn from(error: simplicity::types::Error) -> Self { - Self::CannotCompile { source: error } + Self::CompileError(crate::compile::Error::TypeError(error)) } }