rune/runtime/
vm_error.rs

1use core::convert::Infallible;
2use core::fmt;
3
4use ::rust_alloc::boxed::Box;
5use ::rust_alloc::sync::Arc;
6
7use crate::alloc::error::CustomError;
8use crate::alloc::prelude::*;
9use crate::alloc::{self, String};
10use crate::compile::meta;
11use crate::runtime::unit::{BadInstruction, BadJump};
12use crate::{Any, Hash, ItemBuf};
13
14use super::{
15    AccessError, AccessErrorKind, AnyObjError, AnyObjErrorKind, AnyTypeInfo, BoxedPanic, CallFrame,
16    DynArgsUsed, DynamicTakeError, ExecutionState, MaybeTypeOf, Panic, Protocol, SliceError,
17    StackError, StaticString, TypeInfo, TypeOf, Unit, Vm, VmHaltInfo,
18};
19
20/// A virtual machine error which includes tracing information.
21pub struct VmError {
22    pub(crate) inner: Box<VmErrorInner>,
23}
24
25impl VmError {
26    pub(crate) fn new<E>(error: E) -> Self
27    where
28        VmErrorKind: From<E>,
29    {
30        Self {
31            inner: Box::new(VmErrorInner {
32                error: VmErrorAt {
33                    #[cfg(feature = "emit")]
34                    index: 0,
35                    kind: VmErrorKind::from(error),
36                },
37                chain: ::rust_alloc::vec::Vec::new(),
38                stacktrace: ::rust_alloc::vec::Vec::new(),
39            }),
40        }
41    }
42
43    /// Construct an error containing a panic.
44    pub fn panic<D>(message: D) -> Self
45    where
46        D: 'static + BoxedPanic,
47    {
48        Self::from(Panic::custom(message))
49    }
50
51    /// Construct an expectation error. The actual type received is `actual`,
52    /// but we expected `E`.
53    pub fn expected<E>(actual: TypeInfo) -> Self
54    where
55        E: ?Sized + TypeOf,
56    {
57        Self::from(VmErrorKind::expected::<E>(actual))
58    }
59
60    /// Get the location where the error happened.
61    pub fn at(&self) -> &VmErrorAt {
62        &self.inner.error
63    }
64
65    /// Get the full backtrace of errors and their corresponding instructions.
66    pub fn chain(&self) -> &[VmErrorAt] {
67        &self.inner.chain
68    }
69
70    /// Construct an overflow error.
71    pub fn overflow() -> Self {
72        Self::from(VmErrorKind::Overflow)
73    }
74
75    /// Get the first error location.
76    pub fn first_location(&self) -> Option<&VmErrorLocation> {
77        self.inner.stacktrace.first()
78    }
79
80    pub(crate) fn into_kind(self) -> VmErrorKind {
81        self.inner.error.kind
82    }
83}
84
85impl fmt::Display for VmError {
86    #[inline]
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        self.inner.error.fmt(f)
89    }
90}
91
92impl fmt::Debug for VmError {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        f.debug_struct("VmError")
95            .field("error", &self.inner.error)
96            .field("chain", &self.inner.chain)
97            .field("stacktrace", &self.inner.stacktrace)
98            .finish()
99    }
100}
101
102impl core::error::Error for VmError {}
103
104pub mod sealed {
105    use crate::runtime::VmResult;
106    pub trait Sealed {}
107    impl<T> Sealed for VmResult<T> {}
108    impl<T, E> Sealed for Result<T, E> {}
109}
110
111/// Trait used to convert result types to [`VmResult`].
112#[doc(hidden)]
113pub trait TryFromResult: self::sealed::Sealed {
114    /// The ok type produced by the conversion.
115    type Ok;
116
117    /// The conversion method itself.
118    fn try_from_result(value: Self) -> VmResult<Self::Ok>;
119}
120
121/// Helper to coerce one result type into [`VmResult`].
122///
123/// Despite being public, this is actually private API (`#[doc(hidden)]`). Use
124/// at your own risk.
125#[doc(hidden)]
126#[inline(always)]
127#[allow(clippy::unit_arg)]
128pub fn try_result<T>(result: T) -> VmResult<T::Ok>
129where
130    T: TryFromResult,
131{
132    T::try_from_result(result)
133}
134
135impl<T> TryFromResult for VmResult<T> {
136    type Ok = T;
137
138    #[inline]
139    fn try_from_result(value: Self) -> VmResult<T> {
140        value
141    }
142}
143
144impl<T, E> TryFromResult for Result<T, E>
145where
146    VmError: From<E>,
147{
148    type Ok = T;
149
150    #[inline]
151    fn try_from_result(value: Self) -> VmResult<T> {
152        match value {
153            Ok(ok) => VmResult::Ok(ok),
154            Err(err) => VmResult::Err(VmError::from(err)),
155        }
156    }
157}
158
159/// A single unit producing errors.
160#[derive(Debug)]
161#[non_exhaustive]
162pub struct VmErrorLocation {
163    /// Associated unit.
164    pub unit: Arc<Unit>,
165    /// Frozen instruction pointer.
166    pub ip: usize,
167    /// All lower call frames before the unwind trigger point
168    pub frames: ::rust_alloc::vec::Vec<CallFrame>,
169}
170
171#[derive(Debug)]
172#[non_exhaustive]
173pub struct VmErrorAt {
174    /// Index into the backtrace which contains information of what caused this error.
175    #[cfg(feature = "emit")]
176    index: usize,
177    /// The kind of error.
178    kind: VmErrorKind,
179}
180
181impl VmErrorAt {
182    /// Get the instruction which caused the error.
183    #[cfg(feature = "emit")]
184    pub(crate) fn index(&self) -> usize {
185        self.index
186    }
187
188    #[cfg(feature = "emit")]
189    pub(crate) fn kind(&self) -> &VmErrorKind {
190        &self.kind
191    }
192}
193
194impl fmt::Display for VmErrorAt {
195    #[inline]
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        self.kind.fmt(f)
198    }
199}
200
201#[non_exhaustive]
202pub(crate) struct VmErrorInner {
203    pub(crate) error: VmErrorAt,
204    pub(crate) chain: ::rust_alloc::vec::Vec<VmErrorAt>,
205    pub(crate) stacktrace: ::rust_alloc::vec::Vec<VmErrorLocation>,
206}
207
208/// A result produced by the virtual machine.
209#[must_use]
210pub enum VmResult<T> {
211    /// A produced value.
212    Ok(T),
213    /// Multiple errors with locations included.
214    Err(VmError),
215}
216
217impl<T> VmResult<T> {
218    /// Construct a result containing a panic.
219    #[inline]
220    pub fn panic<D>(message: D) -> Self
221    where
222        D: 'static + BoxedPanic,
223    {
224        Self::err(Panic::custom(message))
225    }
226
227    /// Construct an expectation error. The actual type received is `actual`,
228    /// but we expected `E`.
229    #[inline]
230    pub fn expected<E>(actual: TypeInfo) -> Self
231    where
232        E: ?Sized + TypeOf,
233    {
234        Self::Err(VmError::expected::<E>(actual))
235    }
236
237    /// Test if the result is an ok.
238    #[inline]
239    pub fn is_ok(&self) -> bool {
240        matches!(self, Self::Ok(..))
241    }
242
243    /// Test if the result is an error.
244    #[inline]
245    pub fn is_err(&self) -> bool {
246        matches!(self, Self::Err(..))
247    }
248
249    /// Expect a value or panic.
250    #[inline]
251    #[track_caller]
252    pub fn expect(self, msg: &str) -> T {
253        self.into_result().expect(msg)
254    }
255
256    /// Unwrap the interior value.
257    #[inline]
258    #[track_caller]
259    pub fn unwrap(self) -> T {
260        self.into_result().unwrap()
261    }
262
263    /// Convert a [`VmResult`] into a [`Result`].
264    #[inline]
265    pub fn into_result(self) -> Result<T, VmError> {
266        match self {
267            Self::Ok(value) => Ok(value),
268            Self::Err(error) => Err(error),
269        }
270    }
271
272    /// Construct a new error from a type that can be converted into a
273    /// [`VmError`].
274    pub fn err<E>(error: E) -> Self
275    where
276        VmError: From<E>,
277    {
278        Self::Err(VmError::from(error))
279    }
280
281    /// Apply the given frame to the current result.
282    pub(crate) fn with_vm(self, vm: &Vm) -> Self {
283        match self {
284            Self::Ok(ok) => Self::Ok(ok),
285            Self::Err(mut err) => {
286                err.inner.stacktrace.push(VmErrorLocation {
287                    unit: vm.unit().clone(),
288                    ip: vm.last_ip(),
289                    frames: vm.call_frames().to_vec(),
290                });
291
292                Self::Err(err)
293            }
294        }
295    }
296
297    /// Add auxilliary errors if appropriate.
298    #[inline]
299    pub(crate) fn with_error<E, O>(self, error: E) -> Self
300    where
301        E: FnOnce() -> O,
302        VmErrorKind: From<O>,
303    {
304        match self {
305            Self::Ok(ok) => Self::Ok(ok),
306            Self::Err(mut err) => {
307                #[cfg(feature = "emit")]
308                let index = err.inner.stacktrace.len();
309
310                err.inner.chain.push(VmErrorAt {
311                    #[cfg(feature = "emit")]
312                    index,
313                    kind: VmErrorKind::from(error()),
314                });
315
316                Self::Err(err)
317            }
318        }
319    }
320}
321
322impl<T> MaybeTypeOf for VmResult<T>
323where
324    T: MaybeTypeOf,
325{
326    #[inline]
327    fn maybe_type_of() -> alloc::Result<meta::DocType> {
328        T::maybe_type_of()
329    }
330}
331
332cfg_std! {
333    impl<T> ::std::process::Termination for VmResult<T> {
334        #[inline]
335        fn report(self) -> ::std::process::ExitCode {
336            match self {
337                VmResult::Ok(_) => ::std::process::ExitCode::SUCCESS,
338                VmResult::Err(_) => ::std::process::ExitCode::FAILURE,
339            }
340        }
341    }
342}
343
344impl<E> From<E> for VmError
345where
346    VmErrorKind: From<E>,
347{
348    fn from(error: E) -> Self {
349        Self::new(error)
350    }
351}
352
353impl<E> From<CustomError<E>> for VmError
354where
355    VmError: From<E>,
356{
357    #[inline]
358    fn from(error: CustomError<E>) -> Self {
359        match error {
360            CustomError::Custom(error) => Self::from(error),
361            CustomError::Error(error) => VmError::new(error),
362        }
363    }
364}
365
366impl<const N: usize> From<[VmErrorKind; N]> for VmError {
367    fn from(kinds: [VmErrorKind; N]) -> Self {
368        let mut it = kinds.into_iter();
369
370        let first = match it.next() {
371            None => VmErrorKind::Panic {
372                reason: Panic::custom("Unknown error"),
373            },
374            Some(first) => first,
375        };
376
377        let mut chain = ::rust_alloc::vec::Vec::with_capacity(it.len());
378
379        for kind in it {
380            chain.push(VmErrorAt {
381                #[cfg(feature = "emit")]
382                index: 0,
383                kind,
384            });
385        }
386
387        Self {
388            inner: Box::new(VmErrorInner {
389                error: VmErrorAt {
390                    #[cfg(feature = "emit")]
391                    index: 0,
392                    kind: first,
393                },
394                chain,
395                stacktrace: ::rust_alloc::vec::Vec::new(),
396            }),
397        }
398    }
399}
400
401impl From<Panic> for VmErrorKind {
402    #[inline]
403    fn from(reason: Panic) -> Self {
404        VmErrorKind::Panic { reason }
405    }
406}
407
408/// An opaque simple runtime error.
409#[cfg_attr(test, derive(PartialEq))]
410pub struct RuntimeError {
411    error: VmErrorKind,
412}
413
414impl RuntimeError {
415    pub(crate) fn new(error: VmErrorKind) -> Self {
416        Self { error }
417    }
418
419    pub(crate) fn into_vm_error_kind(self) -> VmErrorKind {
420        self.error
421    }
422
423    /// Construct an error containing a panic.
424    pub fn panic<D>(message: D) -> Self
425    where
426        D: 'static + BoxedPanic,
427    {
428        Self::new(VmErrorKind::from(Panic::custom(message)))
429    }
430
431    /// Bad argument count.
432    pub fn bad_argument_count(actual: usize, expected: usize) -> Self {
433        Self::new(VmErrorKind::BadArgumentCount { actual, expected })
434    }
435
436    /// Construct an expected error.
437    pub fn expected<T>(actual: TypeInfo) -> Self
438    where
439        T: ?Sized + TypeOf,
440    {
441        Self::new(VmErrorKind::Expected {
442            expected: T::type_info(),
443            actual,
444        })
445    }
446
447    /// Construct an expected error from any.
448    pub(crate) fn expected_any<T>(actual: TypeInfo) -> Self
449    where
450        T: Any,
451    {
452        Self::new(VmErrorKind::Expected {
453            expected: TypeInfo::any::<T>(),
454            actual,
455        })
456    }
457
458    /// Construct an expected any error.
459    pub(crate) fn expected_any_obj(actual: TypeInfo) -> Self {
460        Self::new(VmErrorKind::ExpectedAny { actual })
461    }
462
463    /// Indicate that a constant constructor is missing.
464    pub(crate) fn missing_constant_constructor(hash: Hash) -> Self {
465        Self::new(VmErrorKind::MissingConstantConstructor { hash })
466    }
467
468    pub(crate) fn expected_empty(actual: TypeInfo) -> Self {
469        Self::new(VmErrorKind::ExpectedEmpty { actual })
470    }
471
472    pub(crate) fn expected_tuple(actual: TypeInfo) -> Self {
473        Self::new(VmErrorKind::ExpectedTuple { actual })
474    }
475
476    pub(crate) fn expected_struct(actual: TypeInfo) -> Self {
477        Self::new(VmErrorKind::ExpectedStruct { actual })
478    }
479}
480
481#[allow(non_snake_case)]
482impl RuntimeError {
483    #[doc(hidden)]
484    #[inline]
485    pub fn __rune_macros__missing_struct_field(target: &'static str, name: &'static str) -> Self {
486        Self::new(VmErrorKind::MissingStructField { target, name })
487    }
488
489    #[doc(hidden)]
490    #[inline]
491    pub fn __rune_macros__missing_variant(name: &str) -> alloc::Result<Self> {
492        Ok(Self::new(VmErrorKind::MissingVariant {
493            name: name.try_to_owned()?,
494        }))
495    }
496
497    #[doc(hidden)]
498    #[inline]
499    pub fn __rune_macros__expected_variant(actual: TypeInfo) -> Self {
500        Self::new(VmErrorKind::ExpectedVariant { actual })
501    }
502
503    #[doc(hidden)]
504    #[inline]
505    pub fn __rune_macros__missing_variant_name() -> Self {
506        Self::new(VmErrorKind::MissingVariantName)
507    }
508
509    #[doc(hidden)]
510    #[inline]
511    pub fn __rune_macros__missing_tuple_index(target: &'static str, index: usize) -> Self {
512        Self::new(VmErrorKind::MissingTupleIndex { target, index })
513    }
514
515    #[doc(hidden)]
516    #[inline]
517    pub fn __rune_macros__unsupported_object_field_get(target: AnyTypeInfo) -> Self {
518        Self::new(VmErrorKind::UnsupportedObjectFieldGet {
519            target: TypeInfo::from(target),
520        })
521    }
522
523    #[doc(hidden)]
524    #[inline]
525    pub fn __rune_macros__unsupported_tuple_index_get(target: AnyTypeInfo, index: usize) -> Self {
526        Self::new(VmErrorKind::UnsupportedTupleIndexGet {
527            target: TypeInfo::from(target),
528            index,
529        })
530    }
531}
532
533impl fmt::Debug for RuntimeError {
534    #[inline]
535    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536        self.error.fmt(f)
537    }
538}
539
540impl From<Infallible> for RuntimeError {
541    #[inline]
542    fn from(error: Infallible) -> Self {
543        match error {}
544    }
545}
546
547impl From<DynamicTakeError> for RuntimeError {
548    #[inline]
549    fn from(value: DynamicTakeError) -> Self {
550        match value {
551            DynamicTakeError::Access(error) => Self::from(error),
552            DynamicTakeError::Alloc(error) => Self::from(error),
553        }
554    }
555}
556
557impl From<VmError> for RuntimeError {
558    #[inline]
559    fn from(error: VmError) -> Self {
560        Self::new(error.into_kind())
561    }
562}
563
564impl From<alloc::Error> for RuntimeError {
565    #[inline]
566    fn from(error: alloc::Error) -> Self {
567        RuntimeError::from(VmErrorKind::from(error))
568    }
569}
570
571impl From<alloc::alloc::AllocError> for RuntimeError {
572    #[inline]
573    fn from(error: alloc::alloc::AllocError) -> Self {
574        RuntimeError::from(VmErrorKind::from(error))
575    }
576}
577
578impl From<AnyObjError> for RuntimeError {
579    fn from(value: AnyObjError) -> Self {
580        match value.into_kind() {
581            AnyObjErrorKind::Cast(expected, actual) => Self::new(VmErrorKind::Expected {
582                expected: TypeInfo::any_type_info(expected),
583                actual,
584            }),
585            AnyObjErrorKind::AccessError(error) => Self::from(error),
586        }
587    }
588}
589
590impl From<AccessError> for RuntimeError {
591    #[inline]
592    fn from(error: AccessError) -> Self {
593        Self {
594            error: VmErrorKind::from(error),
595        }
596    }
597}
598
599impl From<StackError> for RuntimeError {
600    #[inline]
601    fn from(error: StackError) -> Self {
602        Self {
603            error: VmErrorKind::from(error),
604        }
605    }
606}
607
608impl From<AccessErrorKind> for RuntimeError {
609    #[inline]
610    fn from(error: AccessErrorKind) -> Self {
611        Self {
612            error: VmErrorKind::from(AccessError::from(error)),
613        }
614    }
615}
616
617impl From<VmErrorKind> for RuntimeError {
618    #[inline]
619    fn from(error: VmErrorKind) -> Self {
620        Self { error }
621    }
622}
623
624impl fmt::Display for RuntimeError {
625    #[inline]
626    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627        self.error.fmt(f)
628    }
629}
630
631impl core::error::Error for RuntimeError {}
632
633/// The kind of error encountered.
634#[derive(Debug)]
635#[cfg_attr(test, derive(PartialEq))]
636#[doc(hidden)]
637pub(crate) enum VmErrorKind {
638    AllocError {
639        error: alloc::Error,
640    },
641    AccessError {
642        error: AccessError,
643    },
644    StackError {
645        error: StackError,
646    },
647    SliceError {
648        error: SliceError,
649    },
650    BadInstruction {
651        error: BadInstruction,
652    },
653    BadJump {
654        error: BadJump,
655    },
656    DynArgsUsed {
657        error: DynArgsUsed,
658    },
659    Panic {
660        reason: Panic,
661    },
662    NoRunningVm,
663    Halted {
664        halt: VmHaltInfo,
665    },
666    Overflow,
667    Underflow,
668    DivideByZero,
669    MissingEntry {
670        item: ItemBuf,
671        hash: Hash,
672    },
673    MissingEntryHash {
674        hash: Hash,
675    },
676    MissingFunction {
677        hash: Hash,
678    },
679    MissingContextFunction {
680        hash: Hash,
681    },
682    MissingProtocolFunction {
683        protocol: &'static Protocol,
684        instance: TypeInfo,
685    },
686    MissingInstanceFunction {
687        hash: Hash,
688        instance: TypeInfo,
689    },
690    IpOutOfBounds {
691        ip: usize,
692        length: usize,
693    },
694    UnsupportedBinaryOperation {
695        op: &'static str,
696        lhs: TypeInfo,
697        rhs: TypeInfo,
698    },
699    UnsupportedUnaryOperation {
700        op: &'static str,
701        operand: TypeInfo,
702    },
703    MissingStaticString {
704        slot: usize,
705    },
706    MissingStaticBytes {
707        slot: usize,
708    },
709    MissingStaticObjectKeys {
710        slot: usize,
711    },
712    MissingDropSet {
713        set: usize,
714    },
715    MissingRtti {
716        hash: Hash,
717    },
718    BadArgumentCount {
719        actual: usize,
720        expected: usize,
721    },
722    BadEnvironmentCount {
723        actual: usize,
724        expected: usize,
725    },
726    BadArgument {
727        arg: usize,
728    },
729    UnsupportedIndexSet {
730        target: TypeInfo,
731        index: TypeInfo,
732        value: TypeInfo,
733    },
734    UnsupportedIndexGet {
735        target: TypeInfo,
736        index: TypeInfo,
737    },
738    UnsupportedTupleIndexGet {
739        target: TypeInfo,
740        index: usize,
741    },
742    UnsupportedTupleIndexSet {
743        target: TypeInfo,
744    },
745    UnsupportedObjectSlotIndexGet {
746        target: TypeInfo,
747        field: Arc<StaticString>,
748    },
749    UnsupportedObjectSlotIndexSet {
750        target: TypeInfo,
751        field: Arc<StaticString>,
752    },
753    UnsupportedIs {
754        value: TypeInfo,
755        test_type: TypeInfo,
756    },
757    UnsupportedAs {
758        value: TypeInfo,
759        type_hash: Hash,
760    },
761    UnsupportedCallFn {
762        actual: TypeInfo,
763    },
764    ObjectIndexMissing {
765        slot: usize,
766    },
767    MissingIndex {
768        target: TypeInfo,
769    },
770    MissingIndexInteger {
771        target: TypeInfo,
772        index: VmIntegerRepr,
773    },
774    #[cfg(feature = "alloc")]
775    MissingIndexKey {
776        target: TypeInfo,
777    },
778    OutOfRange {
779        index: VmIntegerRepr,
780        length: VmIntegerRepr,
781    },
782    UnsupportedTryOperand {
783        actual: TypeInfo,
784    },
785    UnsupportedIterRangeInclusive {
786        start: TypeInfo,
787        end: TypeInfo,
788    },
789    UnsupportedIterRangeFrom {
790        start: TypeInfo,
791    },
792    UnsupportedIterRange {
793        start: TypeInfo,
794        end: TypeInfo,
795    },
796    UnsupportedIterNextOperand {
797        actual: TypeInfo,
798    },
799    Expected {
800        expected: TypeInfo,
801        actual: TypeInfo,
802    },
803    ExpectedAny {
804        actual: TypeInfo,
805    },
806    ExpectedNumber {
807        actual: TypeInfo,
808    },
809    ExpectedEmpty {
810        actual: TypeInfo,
811    },
812    ExpectedTuple {
813        actual: TypeInfo,
814    },
815    ExpectedStruct {
816        actual: TypeInfo,
817    },
818    MissingConstantConstructor {
819        hash: Hash,
820    },
821    ValueToIntegerCoercionError {
822        from: VmIntegerRepr,
823        to: &'static str,
824    },
825    IntegerToValueCoercionError {
826        from: VmIntegerRepr,
827        to: &'static str,
828    },
829    ExpectedTupleLength {
830        actual: usize,
831        expected: usize,
832    },
833    ConstNotSupported {
834        actual: TypeInfo,
835    },
836    MissingInterfaceEnvironment,
837    ExpectedExecutionState {
838        actual: ExecutionState,
839    },
840    ExpectedExitedExecutionState {
841        actual: ExecutionState,
842    },
843    GeneratorComplete,
844    FutureCompleted,
845    // Used in rune-macros.
846    MissingVariant {
847        name: String,
848    },
849    MissingField {
850        target: TypeInfo,
851        field: String,
852    },
853    MissingVariantName,
854    MissingStructField {
855        target: &'static str,
856        name: &'static str,
857    },
858    MissingTupleIndex {
859        target: &'static str,
860        index: usize,
861    },
862    ExpectedVariant {
863        actual: TypeInfo,
864    },
865    UnsupportedObjectFieldGet {
866        target: TypeInfo,
867    },
868    IllegalFloatComparison {
869        lhs: f64,
870        rhs: f64,
871    },
872    #[cfg(feature = "alloc")]
873    IllegalFloatOperation {
874        value: f64,
875    },
876    MissingCallFrame,
877    IllegalFormat,
878}
879
880impl fmt::Display for VmErrorKind {
881    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
882        match self {
883            VmErrorKind::AllocError { error } => error.fmt(f),
884            VmErrorKind::AccessError { error } => error.fmt(f),
885            VmErrorKind::StackError { error } => error.fmt(f),
886            VmErrorKind::SliceError { error } => error.fmt(f),
887            VmErrorKind::BadInstruction { error } => error.fmt(f),
888            VmErrorKind::BadJump { error } => error.fmt(f),
889            VmErrorKind::DynArgsUsed { error } => error.fmt(f),
890            VmErrorKind::Panic { reason } => write!(f, "Panicked: {reason}"),
891            VmErrorKind::NoRunningVm => write!(f, "No running virtual machines"),
892            VmErrorKind::Halted { halt } => write!(f, "Halted for unexpected reason `{halt}`"),
893            VmErrorKind::Overflow => write!(f, "Numerical overflow"),
894            VmErrorKind::Underflow => write!(f, "Numerical underflow"),
895            VmErrorKind::DivideByZero => write!(f, "Division by zero"),
896            VmErrorKind::MissingEntry { item, hash } => {
897                write!(f, "Missing entry `{item}` with hash `{hash}`")
898            }
899            VmErrorKind::MissingEntryHash { hash } => {
900                write!(f, "Missing entry with hash `{hash}`")
901            }
902            VmErrorKind::MissingFunction { hash } => {
903                write!(f, "Missing function with hash `{hash}`")
904            }
905            VmErrorKind::MissingContextFunction { hash } => {
906                write!(f, "Missing context function with hash `{hash}`")
907            }
908            VmErrorKind::MissingProtocolFunction { protocol, instance } => {
909                write!(f, "Missing protocol function `{protocol}` for `{instance}`")
910            }
911            VmErrorKind::MissingInstanceFunction { hash, instance } => {
912                write!(f, "Missing instance function `{hash}` for `{instance}`")
913            }
914            VmErrorKind::IpOutOfBounds { ip, length } => write!(
915                f,
916                "Instruction pointer `{ip}` is out-of-bounds `0-{length}`",
917            ),
918            VmErrorKind::UnsupportedBinaryOperation { op, lhs, rhs } => {
919                write!(
920                    f,
921                    "Unsupported binary operation `{op}` on `{lhs}` and `{rhs}`",
922                )
923            }
924            VmErrorKind::UnsupportedUnaryOperation { op, operand } => {
925                write!(f, "Unsupported unary operation `{op}` on {operand}")
926            }
927            VmErrorKind::MissingStaticString { slot } => {
928                write!(f, "Static string slot {slot} does not exist")
929            }
930            VmErrorKind::MissingStaticBytes { slot } => {
931                write!(f, "Static bytes slot {slot} does not exist")
932            }
933            VmErrorKind::MissingStaticObjectKeys { slot } => {
934                write!(f, "Static object keys slot {slot} does not exist")
935            }
936            VmErrorKind::MissingDropSet { set } => {
937                write!(f, "Static drop set {set} does not exist")
938            }
939            VmErrorKind::MissingRtti { hash } => {
940                write!(f, "Missing runtime information for type with hash `{hash}`")
941            }
942            VmErrorKind::BadArgumentCount { actual, expected } => {
943                write!(f, "Wrong number of arguments {actual}, expected {expected}",)
944            }
945            VmErrorKind::BadEnvironmentCount { actual, expected } => write!(
946                f,
947                "Wrong environment size `{actual}`, expected `{expected}`",
948            ),
949            VmErrorKind::BadArgument { arg } => write!(f, "Bad argument #{arg}"),
950            VmErrorKind::UnsupportedIndexSet {
951                target,
952                index,
953                value,
954            } => write!(
955                f,
956                "The index set operation `{target}[{index}] = {value}` is not supported",
957            ),
958            VmErrorKind::UnsupportedIndexGet { target, index } => write!(
959                f,
960                "The index get operation `{target}[{index}]` is not supported",
961            ),
962            VmErrorKind::UnsupportedTupleIndexGet { target, index } => write!(
963                f,
964                "The tuple index get {index} operation is not supported on `{target}`",
965            ),
966            VmErrorKind::UnsupportedTupleIndexSet { target } => write!(
967                f,
968                "The tuple index set operation is not supported on `{target}`",
969            ),
970            VmErrorKind::UnsupportedObjectSlotIndexGet { target, field } => {
971                write!(f, "Field `{field}` not available on `{target}`")
972            }
973            VmErrorKind::UnsupportedObjectSlotIndexSet { target, field } => {
974                write!(f, "Field `{field}` not available to set on `{target}`")
975            }
976            VmErrorKind::UnsupportedIs { value, test_type } => {
977                write!(f, "Operation `{value} is {test_type}` is not supported")
978            }
979            VmErrorKind::UnsupportedAs { value, type_hash } => {
980                write!(f, "Operation `{value} as {type_hash}` is not supported")
981            }
982            VmErrorKind::UnsupportedCallFn { actual } => write!(
983                f,
984                "Type `{actual}` cannot be called since it's not a function",
985            ),
986            VmErrorKind::ObjectIndexMissing { slot } => {
987                write!(f, "Missing index by static string slot `{slot}`")
988            }
989            VmErrorKind::MissingIndex { target } => {
990                write!(f, "Type `{target}` missing index")
991            }
992            VmErrorKind::MissingIndexInteger { target, index } => {
993                write!(f, "Type `{target}` missing integer index `{index}`")
994            }
995            #[cfg(feature = "alloc")]
996            VmErrorKind::MissingIndexKey { target } => {
997                write!(f, "Type `{target}` missing index")
998            }
999            VmErrorKind::OutOfRange { index, length } => write!(
1000                f,
1001                "Index out of bounds, the length is `{length}` but the index is `{index}`",
1002            ),
1003            VmErrorKind::UnsupportedTryOperand { actual } => {
1004                write!(f, "Type `{actual}` is not supported as try operand")
1005            }
1006            VmErrorKind::UnsupportedIterRangeInclusive { start, end } => {
1007                write!(f, "Cannot build an iterator out of {start}..={end}")
1008            }
1009            VmErrorKind::UnsupportedIterRangeFrom { start } => {
1010                write!(f, "Cannot build an iterator out of {start}..")
1011            }
1012            VmErrorKind::UnsupportedIterRange { start, end } => {
1013                write!(f, "Cannot build an iterator out of {start}..{end}")
1014            }
1015            VmErrorKind::UnsupportedIterNextOperand { actual } => {
1016                write!(f, "Type `{actual}` is not supported as iter-next operand")
1017            }
1018            VmErrorKind::Expected { expected, actual } => {
1019                write!(f, "Expected type `{expected}` but found `{actual}`")
1020            }
1021            VmErrorKind::ExpectedAny { actual } => {
1022                write!(f, "Expected `Any` type, but found `{actual}`")
1023            }
1024            VmErrorKind::ExpectedNumber { actual } => {
1025                write!(f, "Expected number type, but found `{actual}`")
1026            }
1027            VmErrorKind::ExpectedEmpty { actual } => {
1028                write!(f, "Expected empty, but found `{actual}`")
1029            }
1030            VmErrorKind::ExpectedTuple { actual } => {
1031                write!(f, "Expected tuple, but found `{actual}`")
1032            }
1033            VmErrorKind::ExpectedStruct { actual } => {
1034                write!(f, "Expected struct, but found `{actual}`")
1035            }
1036            VmErrorKind::MissingConstantConstructor { hash } => {
1037                write!(f, "Missing constant constructor for type with hash {hash}")
1038            }
1039            VmErrorKind::ValueToIntegerCoercionError { from, to } => {
1040                write!(f, "Failed to convert value `{from}` to integer `{to}`")
1041            }
1042            VmErrorKind::IntegerToValueCoercionError { from, to } => {
1043                write!(f, "Failed to convert integer `{from}` to value `{to}`")
1044            }
1045            VmErrorKind::ExpectedTupleLength { actual, expected } => write!(
1046                f,
1047                "Expected a tuple of length `{expected}`, but found one with length `{actual}`",
1048            ),
1049            VmErrorKind::ConstNotSupported { actual } => {
1050                write!(f, "Type `{actual}` can't be converted to a constant value")
1051            }
1052            VmErrorKind::MissingInterfaceEnvironment => {
1053                write!(f, "Missing interface environment")
1054            }
1055            VmErrorKind::ExpectedExecutionState { actual } => {
1056                write!(f, "Expected resume execution state, but was {actual}")
1057            }
1058            VmErrorKind::ExpectedExitedExecutionState { actual } => {
1059                write!(f, "Expected exited execution state, but was {actual}")
1060            }
1061            VmErrorKind::GeneratorComplete => {
1062                write!(f, "Cannot resume a generator that has completed")
1063            }
1064            VmErrorKind::FutureCompleted => write!(f, "Future already completed"),
1065            VmErrorKind::MissingVariant { name } => write!(f, "No variant matching `{name}`"),
1066            VmErrorKind::MissingField { target, field } => {
1067                write!(f, "Missing field `{field}` on `{target}`")
1068            }
1069            VmErrorKind::MissingVariantName => {
1070                write!(f, "missing variant name in runtime information")
1071            }
1072            VmErrorKind::MissingStructField { target, name } => write!(
1073                f,
1074                "missing dynamic field for struct field `{target}::{name}`",
1075            ),
1076            VmErrorKind::MissingTupleIndex { target, index } => write!(
1077                f,
1078                "missing dynamic index #{index} in tuple struct `{target}`",
1079            ),
1080            VmErrorKind::ExpectedVariant { actual } => {
1081                write!(f, "Expected an enum variant, but got `{actual}`")
1082            }
1083            VmErrorKind::UnsupportedObjectFieldGet { target } => write!(
1084                f,
1085                "The object field get operation is not supported on `{target}`",
1086            ),
1087            VmErrorKind::IllegalFloatComparison { lhs, rhs } => {
1088                write!(
1089                    f,
1090                    "Cannot perform a comparison of the floats {lhs} and {rhs}",
1091                )
1092            }
1093            #[cfg(feature = "alloc")]
1094            VmErrorKind::IllegalFloatOperation { value } => {
1095                write!(f, "Cannot perform operation on float `{value}`")
1096            }
1097            VmErrorKind::MissingCallFrame => {
1098                write!(f, "Missing call frame for internal vm call")
1099            }
1100            VmErrorKind::IllegalFormat => {
1101                write!(f, "Value cannot be formatted")
1102            }
1103        }
1104    }
1105}
1106
1107impl From<RuntimeError> for VmErrorKind {
1108    #[inline]
1109    fn from(value: RuntimeError) -> Self {
1110        value.into_vm_error_kind()
1111    }
1112}
1113
1114impl From<DynamicTakeError> for VmErrorKind {
1115    #[inline]
1116    fn from(value: DynamicTakeError) -> Self {
1117        match value {
1118            DynamicTakeError::Access(error) => Self::from(error),
1119            DynamicTakeError::Alloc(error) => Self::from(error),
1120        }
1121    }
1122}
1123
1124impl From<AnyObjError> for VmErrorKind {
1125    #[inline]
1126    fn from(error: AnyObjError) -> Self {
1127        Self::from(RuntimeError::from(error))
1128    }
1129}
1130
1131impl From<Infallible> for VmErrorKind {
1132    #[inline]
1133    fn from(error: Infallible) -> Self {
1134        match error {}
1135    }
1136}
1137
1138impl From<AccessError> for VmErrorKind {
1139    #[inline]
1140    fn from(error: AccessError) -> Self {
1141        VmErrorKind::AccessError { error }
1142    }
1143}
1144
1145impl From<StackError> for VmErrorKind {
1146    #[inline]
1147    fn from(error: StackError) -> Self {
1148        VmErrorKind::StackError { error }
1149    }
1150}
1151
1152impl From<SliceError> for VmErrorKind {
1153    #[inline]
1154    fn from(error: SliceError) -> Self {
1155        VmErrorKind::SliceError { error }
1156    }
1157}
1158
1159impl From<BadInstruction> for VmErrorKind {
1160    #[inline]
1161    fn from(error: BadInstruction) -> Self {
1162        VmErrorKind::BadInstruction { error }
1163    }
1164}
1165
1166impl From<BadJump> for VmErrorKind {
1167    #[inline]
1168    fn from(error: BadJump) -> Self {
1169        VmErrorKind::BadJump { error }
1170    }
1171}
1172
1173impl From<DynArgsUsed> for VmErrorKind {
1174    #[inline]
1175    fn from(error: DynArgsUsed) -> Self {
1176        VmErrorKind::DynArgsUsed { error }
1177    }
1178}
1179
1180impl From<alloc::Error> for VmErrorKind {
1181    #[inline]
1182    fn from(error: alloc::Error) -> Self {
1183        VmErrorKind::AllocError { error }
1184    }
1185}
1186
1187impl From<alloc::alloc::AllocError> for VmErrorKind {
1188    #[inline]
1189    fn from(error: alloc::alloc::AllocError) -> Self {
1190        VmErrorKind::AllocError {
1191            error: error.into(),
1192        }
1193    }
1194}
1195
1196impl VmErrorKind {
1197    /// Bad argument.
1198    pub(crate) fn bad_argument(arg: usize) -> Self {
1199        Self::BadArgument { arg }
1200    }
1201
1202    /// Construct an expected error.
1203    pub(crate) fn expected<T>(actual: TypeInfo) -> Self
1204    where
1205        T: ?Sized + TypeOf,
1206    {
1207        Self::Expected {
1208            expected: T::type_info(),
1209            actual,
1210        }
1211    }
1212}
1213
1214#[derive(Debug, Clone, Copy)]
1215#[cfg_attr(test, derive(PartialEq))]
1216enum VmIntegerReprKind {
1217    Signed(i128),
1218    Unsigned(u128),
1219    Isize(isize),
1220    Usize(usize),
1221}
1222
1223/// A type-erased integer representation.
1224#[derive(Clone)]
1225#[cfg_attr(test, derive(PartialEq))]
1226pub(crate) struct VmIntegerRepr {
1227    kind: VmIntegerReprKind,
1228}
1229
1230impl VmIntegerRepr {
1231    #[inline]
1232    fn new(kind: VmIntegerReprKind) -> Self {
1233        Self { kind }
1234    }
1235}
1236
1237macro_rules! impl_from {
1238    ($($variant:ident => [$($ty:ty),* $(,)?]),* $(,)?) => {
1239        $($(
1240            impl From<$ty> for VmIntegerRepr {
1241                #[inline]
1242                fn from(value: $ty) -> Self {
1243                    Self::new(VmIntegerReprKind::$variant(From::from(value)))
1244                }
1245            }
1246        )*)*
1247    };
1248}
1249
1250impl_from! {
1251    Signed => [i8, i16, i32, i64, i128],
1252    Unsigned => [u8, u16, u32, u64, u128],
1253    Isize => [isize],
1254    Usize => [usize],
1255}
1256
1257impl fmt::Display for VmIntegerRepr {
1258    #[inline]
1259    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1260        match &self.kind {
1261            VmIntegerReprKind::Signed(value) => value.fmt(f),
1262            VmIntegerReprKind::Unsigned(value) => value.fmt(f),
1263            VmIntegerReprKind::Isize(value) => value.fmt(f),
1264            VmIntegerReprKind::Usize(value) => value.fmt(f),
1265        }
1266    }
1267}
1268
1269impl fmt::Debug for VmIntegerRepr {
1270    #[inline]
1271    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1272        self.kind.fmt(f)
1273    }
1274}