Skip to content

Commit fb129a4

Browse files
authored
Merge pull request #6497 from jferrant/chore/aac-rename-parse-errors
Chore/aac rename parse errors and add descriptions
2 parents 0c88f08 + a9d4c77 commit fb129a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1368
-1173
lines changed

clarity-types/src/errors/ast.rs

Lines changed: 180 additions & 81 deletions
Large diffs are not rendered by default.

clarity-types/src/errors/mod.rs

Lines changed: 105 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub mod lexer;
2121
use std::{error, fmt};
2222

2323
pub use analysis::{CheckErrorKind, StaticCheckError};
24-
pub use ast::{ParseError, ParseErrors, ParseResult};
24+
pub use ast::{ParseError, ParseErrorKind, ParseResult};
2525
pub use cost::CostErrors;
2626
pub use lexer::LexerError;
2727
#[cfg(feature = "rusqlite")]
@@ -33,8 +33,12 @@ use crate::types::{FunctionIdentifier, Value};
3333

3434
pub type StackTrace = Vec<FunctionIdentifier>;
3535

36+
/// Wraps error types that do not implement [`PartialEq`], enabling their
37+
/// use in enums that implement the trait. Any two `IncomparableError` values
38+
/// are always considered unequal.
3639
#[derive(Debug)]
3740
pub struct IncomparableError<T> {
41+
/// The wrapped error value.
3842
pub err: T,
3943
}
4044

@@ -52,70 +56,141 @@ pub enum VmExecutionError {
5256
/// violating type or resource constraints (e.g., excessive stack depth).
5357
/// The `CheckErrorKind` wraps the specific type-checking error encountered at runtime.
5458
Unchecked(CheckErrorKind),
55-
Interpreter(InterpreterError),
59+
/// A critical, unrecoverable bug within the VM's internal logic.
60+
///
61+
/// The presence of this error indicates a violation of one of the VM's
62+
/// invariants or a corrupted state. This is **not** an error in the user's
63+
/// Clarity code, but a bug in the VM's Rust implementation.
64+
///
65+
/// # Example
66+
/// The VM's evaluation loop attempts to `pop` from an empty internal call stack,
67+
/// indicating a mismatch in function entry/exit logic.
68+
Internal(VmInternalError),
5669
/// Errors that occur during runtime execution of Clarity code, such as arithmetic errors or
5770
/// invalid operations, expected as part of contract evaluation.
5871
/// The `RuntimeErrorType` wraps the specific runtime error, and the `Option<StackTrace>` provides
5972
/// an optional stack trace for debugging, if available.
60-
Runtime(RuntimeErrorType, Option<StackTrace>),
73+
Runtime(RuntimeError, Option<StackTrace>),
6174
/// Errors triggered during Clarity contract evaluation that cause early termination with
6275
/// insufficient results (e.g., unwrapping an empty `Option`).
6376
/// The `EarlyReturnError` wraps the specific early return condition, detailing the premature
6477
/// termination cause.
6578
EarlyReturn(EarlyReturnError),
6679
}
6780

68-
/// InterpreterErrors are errors that *should never* occur.
69-
/// Test executions may trigger these errors.
81+
/// Represents an internal, unrecoverable error within the Clarity VM.
82+
///
83+
/// These errors signify a bug in the VM's logic or a violation of its internal
84+
/// invariants. They are not meant to be caught or handled by Clarity contracts.
7085
#[derive(Debug, PartialEq)]
71-
pub enum InterpreterError {
86+
pub enum VmInternalError {
87+
/// Raised when the VM encounters an invalid or malformed `SymbolicExpression`
88+
/// e.g., bad variable name or missing argument.
89+
/// The `String` provides a message describing the specific issue.
7290
BadSymbolicRepresentation(String),
73-
InterpreterError(String),
91+
/// A generic, unexpected internal error, indicating a logic failure within
92+
/// the VM.
93+
/// The `String` provides a message describing the specific failure.
94+
InvariantViolation(String), // TODO: merge with VmInternalError::Expect
95+
/// The VM failed to produce the final `AssetMap` when finalizing the
96+
/// execution environment for a transaction.
7497
FailedToConstructAssetTable,
98+
/// The VM failed to produce the final `EventBatch` when finalizing the
99+
/// execution environment for a transaction.
75100
FailedToConstructEventBatch,
101+
/// An error occurred during an interaction with the database.
102+
/// The parameter contains the corresponding SQLite error.
76103
#[cfg(feature = "rusqlite")]
77104
SqliteError(IncomparableError<SqliteError>),
105+
/// The file path provided for the MARF database is invalid because it
106+
/// contains non-UTF-8 characters.
78107
BadFileName,
108+
/// The VM failed to create the necessary directory for the MARF persistent
109+
/// storage. Likely due to a file system permissions error or an invalid path
79110
FailedToCreateDataDirectory,
111+
/// A failure occurred within the MARF implementation.
112+
/// The `String` provides a message describing the specific failure.
80113
MarfFailure(String),
114+
/// Failed to construct a tuple value from provided data because it did not
115+
/// match the expected type signature.
81116
FailureConstructingTupleWithType,
117+
/// Failed to construct a list value from provided data because it
118+
/// did not match the expected type signature.
82119
FailureConstructingListWithType,
120+
/// An STX transfer failed due to insufficient balance.
83121
InsufficientBalance,
122+
/// A generic error occurred during a database operation.
123+
/// The `String` represents a descriptive message detailing the specific issue.
84124
DBError(String),
125+
/// An internal expectation or assertion failed. This is used for conditions
126+
/// that are believed to be unreachable but are handled gracefully to prevent
127+
/// a panic.
128+
/// The `String` provides a message describing the failed expectation.
85129
Expect(String),
86130
}
87131

88-
/// RuntimeErrors are errors that smart contracts are expected
89-
/// to be able to trigger during execution (e.g., arithmetic errors)
132+
/// Runtime errors that Clarity smart contracts are expected to trigger during execution in the virtual
133+
/// machine, such as arithmetic errors, invalid operations, or blockchain-specific issues. These errors
134+
/// are distinct from static analysis errors and occur during dynamic evaluation of contract code.
90135
#[derive(Debug, PartialEq)]
91-
pub enum RuntimeErrorType {
136+
pub enum RuntimeError {
137+
/// A generic arithmetic error encountered during contract execution.
138+
/// The `String` represents a descriptive message detailing the specific arithmetic issue.
92139
Arithmetic(String),
140+
/// An arithmetic operation exceeded the maximum value for the data type (e.g., `u128`).
93141
ArithmeticOverflow,
142+
/// An arithmetic operation resulted in a value below zero for an unsigned type.
94143
ArithmeticUnderflow,
144+
/// Attempt to increase token supply beyond the maximum limit.
145+
/// The first u128 represents the attempted new supply (current supply plus increase),
146+
/// and the second represents the maximum allowed supply.
95147
SupplyOverflow(u128, u128),
148+
/// Attempt to decrease token supply below zero.
149+
/// The first `u128` represents the current token supply, and the second represents the attempted decrease amount.
96150
SupplyUnderflow(u128, u128),
151+
/// Attempt to divide or compute modulo by zero.
97152
DivisionByZero,
98-
// error in parsing types
99-
ParseError(String),
100-
// error in parsing the AST
153+
/// Failure to parse types dynamically during contract execution.
154+
/// The `String` represents the specific parsing issue, such as invalid data formats.
155+
TypeParseFailure(String),
156+
/// Failure to parse the abstract syntax tree (AST) during dynamic evaluation.
157+
/// The `Box<ParseError>` wraps the specific parsing error encountered, detailing code interpretation issues.
101158
ASTError(Box<ParseError>),
159+
/// The call stack exceeded the virtual machine's maximum depth.
102160
MaxStackDepthReached,
161+
/// The execution context depth exceeded the virtual machine's limit.
103162
MaxContextDepthReached,
163+
/// Attempt to construct an invalid or unsupported type at runtime (e.g., malformed data structure).
104164
BadTypeConstruction,
165+
/// Reference to an invalid or out-of-bounds block height.
166+
/// The `String` represents the string representation of the queried block height that was invalid.
105167
BadBlockHeight(String),
168+
/// Attempt to interact with a non-existent token (e.g., in NFT or fungible token operations).
106169
NoSuchToken,
170+
/// Feature or function not yet implemented in the virtual machine.
107171
NotImplemented,
172+
/// No caller principal available in the current execution context.
108173
NoCallerInContext,
174+
/// No sender principal available in the current execution context.
109175
NoSenderInContext,
176+
/// Invalid name-value pair in contract data (e.g., map keys).
177+
/// The `&'static str` represents the name of the invalid pair, and the `String` represents the offending value.
110178
BadNameValue(&'static str, String),
179+
/// Reference to a non-existent block header hash.
180+
/// The `BlockHeaderHash` represents the unknown block header hash.
111181
UnknownBlockHeaderHash(BlockHeaderHash),
182+
/// Invalid block hash provided (e.g., incorrect format or length).
183+
/// The `Vec<u8>` represents the invalid block hash data.
112184
BadBlockHash(Vec<u8>),
185+
/// Failed to unwrap an `Optional` (`none`) or `Response` (`err` or `ok`) Clarity value.
113186
UnwrapFailure,
187+
/// Attempt to set metadata (e.g., for NFTs or tokens) that was already initialized.
114188
MetadataAlreadySet,
115-
// pox-locking errors
189+
/// Interaction with a deprecated or inactive Proof of Transfer (PoX) contract.
116190
DefunctPoxContract,
191+
/// Attempt to lock STX for stacking when already locked in an active PoX cycle.
117192
PoxAlreadyLocked,
118-
193+
/// Block time unavailable during execution.
119194
BlockTimeNotAvailable,
120195
}
121196

@@ -146,7 +221,7 @@ impl PartialEq<VmExecutionError> for VmExecutionError {
146221
(VmExecutionError::Runtime(x, _), VmExecutionError::Runtime(y, _)) => x == y,
147222
(VmExecutionError::Unchecked(x), VmExecutionError::Unchecked(y)) => x == y,
148223
(VmExecutionError::EarlyReturn(x), VmExecutionError::EarlyReturn(y)) => x == y,
149-
(VmExecutionError::Interpreter(x), VmExecutionError::Interpreter(y)) => x == y,
224+
(VmExecutionError::Internal(x), VmExecutionError::Internal(y)) => x == y,
150225
_ => false,
151226
}
152227
}
@@ -170,7 +245,7 @@ impl fmt::Display for VmExecutionError {
170245
}
171246
}
172247

173-
impl fmt::Display for RuntimeErrorType {
248+
impl fmt::Display for RuntimeError {
174249
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
175250
write!(f, "{self:?}")
176251
}
@@ -182,7 +257,7 @@ impl error::Error for VmExecutionError {
182257
}
183258
}
184259

185-
impl error::Error for RuntimeErrorType {
260+
impl error::Error for RuntimeError {
186261
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
187262
None
188263
}
@@ -191,30 +266,30 @@ impl error::Error for RuntimeErrorType {
191266
impl From<ParseError> for VmExecutionError {
192267
fn from(err: ParseError) -> Self {
193268
match *err.err {
194-
ParseErrors::InterpreterFailure => VmExecutionError::from(InterpreterError::Expect(
269+
ParseErrorKind::InterpreterFailure => VmExecutionError::from(VmInternalError::Expect(
195270
"Unexpected interpreter failure during parsing".into(),
196271
)),
197-
_ => VmExecutionError::from(RuntimeErrorType::ASTError(Box::new(err))),
272+
_ => VmExecutionError::from(RuntimeError::ASTError(Box::new(err))),
198273
}
199274
}
200275
}
201276

202277
impl From<CostErrors> for VmExecutionError {
203278
fn from(err: CostErrors) -> Self {
204279
match err {
205-
CostErrors::InterpreterFailure => VmExecutionError::from(InterpreterError::Expect(
280+
CostErrors::InterpreterFailure => VmExecutionError::from(VmInternalError::Expect(
206281
"Interpreter failure during cost calculation".into(),
207282
)),
208-
CostErrors::Expect(s) => VmExecutionError::from(InterpreterError::Expect(format!(
283+
CostErrors::Expect(s) => VmExecutionError::from(VmInternalError::Expect(format!(
209284
"Interpreter failure during cost calculation: {s}"
210285
))),
211286
other_err => VmExecutionError::from(CheckErrorKind::from(other_err)),
212287
}
213288
}
214289
}
215290

216-
impl From<RuntimeErrorType> for VmExecutionError {
217-
fn from(err: RuntimeErrorType) -> Self {
291+
impl From<RuntimeError> for VmExecutionError {
292+
fn from(err: RuntimeError) -> Self {
218293
VmExecutionError::Runtime(err, None)
219294
}
220295
}
@@ -237,9 +312,9 @@ impl From<EarlyReturnError> for VmExecutionError {
237312
}
238313
}
239314

240-
impl From<InterpreterError> for VmExecutionError {
241-
fn from(err: InterpreterError) -> Self {
242-
VmExecutionError::Interpreter(err)
315+
impl From<VmInternalError> for VmExecutionError {
316+
fn from(err: VmInternalError) -> Self {
317+
VmExecutionError::Internal(err)
243318
}
244319
}
245320

@@ -272,15 +347,13 @@ mod test {
272347
))))
273348
);
274349
assert_eq!(
275-
VmExecutionError::Interpreter(InterpreterError::InterpreterError("".to_string())),
276-
VmExecutionError::Interpreter(InterpreterError::InterpreterError("".to_string()))
350+
VmExecutionError::Internal(VmInternalError::InvariantViolation("".to_string())),
351+
VmExecutionError::Internal(VmInternalError::InvariantViolation("".to_string()))
277352
);
278353
assert!(
279354
VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(Box::new(Value::Bool(
280355
true
281-
)))) != VmExecutionError::Interpreter(InterpreterError::InterpreterError(
282-
"".to_string()
283-
))
356+
)))) != VmExecutionError::Internal(VmInternalError::InvariantViolation("".to_string()))
284357
);
285358
}
286359
}

clarity-types/src/representations.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use regex::Regex;
2323
use stacks_common::codec::{Error as codec_error, StacksMessageCodec, read_next, write_next};
2424

2525
use crate::Value;
26-
use crate::errors::RuntimeErrorType;
26+
use crate::errors::RuntimeError;
2727
use crate::types::TraitIdentifier;
2828

2929
pub const CONTRACT_MIN_NAME_LENGTH: usize = 1;
@@ -66,17 +66,17 @@ guarded_string!(
6666
"ClarityName",
6767
CLARITY_NAME_REGEX,
6868
MAX_STRING_LEN,
69-
RuntimeErrorType,
70-
RuntimeErrorType::BadNameValue
69+
RuntimeError,
70+
RuntimeError::BadNameValue
7171
);
7272

7373
guarded_string!(
7474
ContractName,
7575
"ContractName",
7676
CONTRACT_NAME_REGEX,
7777
MAX_STRING_LEN,
78-
RuntimeErrorType,
79-
RuntimeErrorType::BadNameValue
78+
RuntimeError,
79+
RuntimeError::BadNameValue
8080
);
8181

8282
impl StacksMessageCodec for ClarityName {

clarity-types/src/tests/representations.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
use rstest::rstest;
1717

18-
use crate::errors::RuntimeErrorType;
18+
use crate::errors::RuntimeError;
1919
use crate::representations::{
2020
CONTRACT_MAX_NAME_LENGTH, CONTRACT_MIN_NAME_LENGTH, ClarityName, ContractName, MAX_STRING_LEN,
2121
};
@@ -73,7 +73,7 @@ fn test_clarity_name_invalid(#[case] name: &str) {
7373
assert!(result.is_err());
7474
assert!(matches!(
7575
result.unwrap_err(),
76-
RuntimeErrorType::BadNameValue(_, _)
76+
RuntimeError::BadNameValue(_, _)
7777
));
7878
}
7979

@@ -157,7 +157,7 @@ fn test_contract_name_invalid(#[case] name: &str) {
157157
assert!(result.is_err());
158158
assert!(matches!(
159159
result.unwrap_err(),
160-
RuntimeErrorType::BadNameValue(_, _)
160+
RuntimeError::BadNameValue(_, _)
161161
));
162162
}
163163

0 commit comments

Comments
 (0)