Skip to main content

rune/runtime/
vm_error.rs

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