foundry_compilers_core/
error.rs1use semver::Version;
2use std::{
3 io,
4 path::{Path, PathBuf},
5};
6use thiserror::Error;
7
8pub type Result<T, E = SolcError> = std::result::Result<T, E>;
9
10#[allow(unused_macros)]
11#[macro_export]
12macro_rules! format_err {
13 ($($tt:tt)*) => {
14 $crate::error::SolcError::msg(format!($($tt)*))
15 };
16}
17
18#[allow(unused_macros)]
19#[macro_export]
20macro_rules! bail {
21 ($($tt:tt)*) => { return Err(format_err!($($tt)*)) };
22}
23
24#[derive(Debug, Error)]
26pub enum SolcError {
27 #[error("solc exited with {0}\n{1}")]
29 SolcError(std::process::ExitStatus, String),
30 #[error("failed to parse a file: {0}")]
31 ParseError(String),
32 #[error("invalid UTF-8 in Solc output")]
33 InvalidUtf8,
34 #[error("missing pragma from Solidity file")]
35 PragmaNotFound,
36 #[error("could not find Solc version locally or upstream")]
37 VersionNotFound,
38 #[error("checksum mismatch for {file}: expected {expected} found {detected} for {version}")]
39 ChecksumMismatch { version: Version, expected: String, detected: String, file: PathBuf },
40 #[error("checksum not found for {version}")]
41 ChecksumNotFound { version: Version },
42 #[error(transparent)]
43 SemverError(#[from] semver::Error),
44 #[error(transparent)]
46 SerdeJson(#[from] serde_json::Error),
47 #[error(transparent)]
49 Io(#[from] SolcIoError),
50 #[error("file could not be resolved due to broken symlink: {0}")]
51 ResolveBadSymlink(SolcIoError),
52 #[error("failed to resolve file: {0}; check configured remappings")]
54 Resolve(SolcIoError),
55 #[error("file cannot be resolved due to mismatch of file name case: {error}.\nFound existing file: {existing_file:?}\nPlease check the case of the import.")]
56 ResolveCaseSensitiveFileName { error: SolcIoError, existing_file: PathBuf },
57 #[error(
58 "{0}\n\t\
59 --> {1}\n\t\
60 {2}"
61 )]
62 FailedResolveImport(Box<SolcError>, PathBuf, PathBuf),
63 #[cfg(feature = "svm-solc")]
64 #[error(transparent)]
65 SvmError(#[from] svm::SvmError),
66 #[error("no contracts found at \"{0}\"")]
67 NoContracts(String),
68 #[error("{0}")]
70 Message(String),
71
72 #[error("no artifact found for `{}:{}`", .0.display(), .1)]
73 ArtifactNotFound(PathBuf, String),
74
75 #[cfg(feature = "project-util")]
76 #[error(transparent)]
77 FsExtra(#[from] fs_extra::error::Error),
78}
79
80impl SolcError {
81 pub fn io(err: io::Error, path: impl Into<PathBuf>) -> Self {
82 SolcIoError::new(err, path).into()
83 }
84
85 pub fn solc_output(output: &std::process::Output) -> Self {
87 let mut msg = String::from_utf8_lossy(&output.stderr);
88 let mut trimmed = msg.trim();
89 if trimmed.is_empty() {
90 msg = String::from_utf8_lossy(&output.stdout);
91 trimmed = msg.trim();
92 if trimmed.is_empty() {
93 trimmed = "<empty output>";
94 }
95 }
96 Self::SolcError(output.status, trimmed.into())
97 }
98
99 pub fn msg(msg: impl std::fmt::Display) -> Self {
101 Self::Message(msg.to_string())
102 }
103}
104
105#[derive(Debug, Error)]
106#[error("\"{}\": {io}", self.path.display())]
107pub struct SolcIoError {
108 io: io::Error,
109 path: PathBuf,
110}
111
112impl SolcIoError {
113 pub fn new(io: io::Error, path: impl Into<PathBuf>) -> Self {
114 Self { io, path: path.into() }
115 }
116
117 pub fn path(&self) -> &Path {
119 &self.path
120 }
121
122 pub fn source(&self) -> &io::Error {
124 &self.io
125 }
126}
127
128impl From<SolcIoError> for io::Error {
129 fn from(err: SolcIoError) -> Self {
130 err.io
131 }
132}