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
423impl From<Infallible> for RuntimeError {
424    #[inline]
425    fn from(error: Infallible) -> Self {
426        match error {}
427    }
428}
429
430from_new! {
431    RuntimeError {
432        alloc::Error,
433        alloc::alloc::AllocError,
434        AccessError,
435        AnySequenceTakeError,
436        AnyObjError,
437        StackError,
438        VmErrorKind,
439        ExpectedType,
440    }
441}
442
443/// The kind of error encountered.
444#[derive(Debug)]
445#[cfg_attr(test, derive(PartialEq))]
446#[doc(hidden)]
447pub(crate) enum VmErrorKind {
448    AllocError {
449        error: alloc::Error,
450    },
451    AccessError {
452        error: AccessError,
453    },
454    StackError {
455        error: StackError,
456    },
457    SliceError {
458        error: SliceError,
459    },
460    BadInstruction {
461        error: BadInstruction,
462    },
463    BadJump {
464        error: BadJump,
465    },
466    DynArgsUsed {
467        error: DynArgsUsed,
468    },
469    Panic {
470        reason: Panic,
471    },
472    NoRunningVm,
473    Halted {
474        halt: VmHaltInfo,
475    },
476    Overflow,
477    Underflow,
478    DivideByZero,
479    MissingEntry {
480        item: ItemBuf,
481        hash: Hash,
482    },
483    MissingEntryHash {
484        hash: Hash,
485    },
486    MissingFunction {
487        hash: Hash,
488    },
489    MissingContextFunction {
490        hash: Hash,
491    },
492    NotOwned {
493        type_info: TypeInfo,
494    },
495    MissingProtocolFunction {
496        protocol: &'static Protocol,
497        instance: TypeInfo,
498    },
499    MissingInstanceFunction {
500        hash: Hash,
501        instance: TypeInfo,
502    },
503    IpOutOfBounds {
504        ip: usize,
505        length: usize,
506    },
507    UnsupportedBinaryOperation {
508        op: &'static str,
509        lhs: TypeInfo,
510        rhs: TypeInfo,
511    },
512    UnsupportedUnaryOperation {
513        op: &'static str,
514        operand: TypeInfo,
515    },
516    MissingStaticString {
517        slot: usize,
518    },
519    MissingStaticBytes {
520        slot: usize,
521    },
522    MissingStaticObjectKeys {
523        slot: usize,
524    },
525    MissingDropSet {
526        set: usize,
527    },
528    MissingGlobals {
529        slot: usize,
530        name: Option<ItemBuf>,
531    },
532    BadGlobalSlot {
533        slot: usize,
534        name: Option<ItemBuf>,
535    },
536    UninitializedGlobal {
537        slot: usize,
538        name: Option<ItemBuf>,
539    },
540    MissingRtti {
541        hash: Hash,
542    },
543    BadArgumentCount {
544        actual: usize,
545        expected: usize,
546    },
547    /// A walk over a value descended more deeply than it is allowed to.
548    ///
549    /// Comparing, ordering, hashing and formatting a value all recurse into the
550    /// values it is made of, so a graph which nests too deeply is reported
551    /// rather than overflowing the stack.
552    MaxValueDepth {
553        max: usize,
554    },
555    /// A value was nested more deeply than a constant is allowed to be.
556    ///
557    /// A `ConstValue` is built, walked, cloned and dropped by recursing over
558    /// it, and the value it is built from is produced by evaluation, so how
559    /// deep it is has nothing to do with how deep the source was.
560    MaxConstDepth {
561        max: usize,
562    },
563    /// A constant is made of more values than it is allowed to be.
564    MaxConstSize {
565        max: usize,
566    },
567    /// The array a constant is stored as does not describe a tree.
568    ///
569    /// A constant is one array of nodes in which every subtree is a contiguous
570    /// run, so an array in which a node claims children it does not have is not
571    /// a constant. Building one here cannot produce such an array; reading one
572    /// back from somewhere else can.
573    MalformedConstValue,
574    /// Executions were nested more deeply than they are allowed to be.
575    ///
576    /// A call which a native function performs is driven by a machine of its
577    /// own, which costs a native frame, so a script which nests them too deeply
578    /// is reported rather than overflowing the stack.
579    MaxExecutionDepth {
580        max: usize,
581    },
582    BadEnvironmentCount {
583        actual: usize,
584        expected: usize,
585    },
586    BadArgument {
587        arg: usize,
588    },
589    UnsupportedIndexSet {
590        target: TypeInfo,
591        index: TypeInfo,
592        value: TypeInfo,
593    },
594    UnsupportedIndexGet {
595        target: TypeInfo,
596        index: TypeInfo,
597    },
598    UnsupportedTupleIndexGet {
599        target: TypeInfo,
600        index: usize,
601    },
602    UnsupportedTupleIndexSet {
603        target: TypeInfo,
604    },
605    UnsupportedObjectSlotIndexGet {
606        target: TypeInfo,
607        field: Arc<StaticString>,
608    },
609    UnsupportedObjectSlotIndexSet {
610        target: TypeInfo,
611        field: Arc<StaticString>,
612    },
613    UnsupportedIs {
614        value: TypeInfo,
615        test_type: TypeInfo,
616    },
617    UnsupportedAs {
618        value: TypeInfo,
619    },
620    UnsupportedAsTarget {
621        value: TypeInfo,
622    },
623    UnsupportedCallFn {
624        actual: TypeInfo,
625    },
626    ObjectIndexMissing {
627        slot: usize,
628    },
629    MissingIndex {
630        target: TypeInfo,
631    },
632    MissingIndexInteger {
633        target: TypeInfo,
634        index: VmIntegerRepr,
635    },
636    MissingIndexKey {
637        target: TypeInfo,
638    },
639    OutOfRange {
640        index: VmIntegerRepr,
641        length: VmIntegerRepr,
642    },
643    UnsupportedTryOperand {
644        actual: TypeInfo,
645    },
646    UnsupportedIterRangeInclusive {
647        start: TypeInfo,
648        end: TypeInfo,
649    },
650    UnsupportedIterRangeFrom {
651        start: TypeInfo,
652    },
653    UnsupportedIterRange {
654        start: TypeInfo,
655        end: TypeInfo,
656    },
657    UnsupportedIterNextOperand {
658        actual: TypeInfo,
659    },
660    ExpectedType {
661        expected: TypeInfo,
662        actual: TypeInfo,
663    },
664    ExpectedAny {
665        actual: TypeInfo,
666    },
667    ExpectedNumber {
668        actual: TypeInfo,
669    },
670    ExpectedEmpty {
671        actual: TypeInfo,
672    },
673    ExpectedTuple {
674        actual: TypeInfo,
675    },
676    ExpectedStruct {
677        actual: TypeInfo,
678    },
679    MissingConstantConstructor {
680        hash: Hash,
681    },
682    ValueToIntegerCoercionError {
683        from: VmIntegerRepr,
684        to: &'static str,
685    },
686    IntegerToValueCoercionError {
687        from: VmIntegerRepr,
688        to: &'static str,
689    },
690    ExpectedTupleLength {
691        actual: usize,
692        expected: usize,
693    },
694    ExpectedVecLength {
695        actual: usize,
696        expected: usize,
697    },
698    ConstNotSupported {
699        actual: TypeInfo,
700    },
701    MissingInterfaceEnvironment,
702    ExpectedExitedExecutionState {
703        actual: ExecutionState,
704    },
705    GeneratorComplete,
706    FutureCompleted,
707    // Used in rune-macros.
708    MissingVariant {
709        name: String,
710    },
711    MissingField {
712        target: TypeInfo,
713        field: String,
714    },
715    MissingVariantName,
716    MissingStructField {
717        target: &'static str,
718        name: &'static str,
719    },
720    MissingTupleIndex {
721        target: &'static str,
722        index: usize,
723    },
724    ExpectedVariant {
725        actual: TypeInfo,
726    },
727    UnsupportedObjectFieldGet {
728        target: TypeInfo,
729    },
730    IllegalFloatComparison {
731        lhs: f64,
732        rhs: f64,
733    },
734    IllegalFloatOperation {
735        value: f64,
736    },
737    MissingCallFrame,
738    IllegalFormat,
739}
740
741impl fmt::Display for VmErrorKind {
742    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
743        match self {
744            VmErrorKind::AllocError { error } => error.fmt(f),
745            VmErrorKind::AccessError { error } => error.fmt(f),
746            VmErrorKind::StackError { error } => error.fmt(f),
747            VmErrorKind::SliceError { error } => error.fmt(f),
748            VmErrorKind::BadInstruction { error } => error.fmt(f),
749            VmErrorKind::BadJump { error } => error.fmt(f),
750            VmErrorKind::DynArgsUsed { error } => error.fmt(f),
751            VmErrorKind::Panic { reason } => write!(f, "Panicked: {reason}"),
752            VmErrorKind::NoRunningVm => write!(f, "No running virtual machines"),
753            // A halt says what the machine did, and each of the three is a
754            // different thing to have happened: one is the host's own limit
755            // doing what it was set to do, and the other two are a function
756            // being called as if it were something it is not.
757            VmErrorKind::Halted { halt } => match halt {
758                VmHaltInfo::Limited => write!(f, "Exhausted the budget it was given"),
759                VmHaltInfo::Yielded => write!(
760                    f,
761                    "Yielded, but was called as if it could not - a generator has to be \
762                     driven through an execution"
763                ),
764                VmHaltInfo::Awaited => write!(
765                    f,
766                    "Awaited, but was called as if it could not - an asynchronous function \
767                     has to be called asynchronously"
768                ),
769            },
770            VmErrorKind::Overflow => write!(f, "Numerical overflow"),
771            VmErrorKind::Underflow => write!(f, "Numerical underflow"),
772            VmErrorKind::DivideByZero => write!(f, "Division by zero"),
773            VmErrorKind::MissingEntry { item, hash } => {
774                write!(f, "Missing entry `{item}` with hash `{hash}`")
775            }
776            VmErrorKind::MissingEntryHash { hash } => {
777                write!(f, "Missing entry with hash `{hash}`")
778            }
779            VmErrorKind::MissingFunction { hash } => {
780                write!(f, "Missing function with hash `{hash}`")
781            }
782            VmErrorKind::MissingContextFunction { hash } => {
783                write!(f, "Missing context function with hash `{hash}`")
784            }
785            VmErrorKind::NotOwned { type_info } => {
786                write!(f, "Cannot use owned operations for {type_info}")
787            }
788            VmErrorKind::MissingProtocolFunction { protocol, instance } => {
789                write!(f, "Missing protocol function `{protocol}` for `{instance}`")
790            }
791            VmErrorKind::MissingInstanceFunction { hash, instance } => {
792                write!(f, "Missing instance function `{hash}` for `{instance}`")
793            }
794            VmErrorKind::IpOutOfBounds { ip, length } => write!(
795                f,
796                "Instruction pointer `{ip}` is out-of-bounds `0-{length}`",
797            ),
798            VmErrorKind::UnsupportedBinaryOperation { op, lhs, rhs } => {
799                write!(
800                    f,
801                    "Unsupported binary operation `{op}` on `{lhs}` and `{rhs}`",
802                )
803            }
804            VmErrorKind::UnsupportedUnaryOperation { op, operand } => {
805                write!(f, "Unsupported unary operation `{op}` on {operand}")
806            }
807            VmErrorKind::MissingStaticString { slot } => {
808                write!(f, "Static string slot {slot} does not exist")
809            }
810            VmErrorKind::MissingStaticBytes { slot } => {
811                write!(f, "Static bytes slot {slot} does not exist")
812            }
813            VmErrorKind::MissingStaticObjectKeys { slot } => {
814                write!(f, "Static object keys slot {slot} does not exist")
815            }
816            VmErrorKind::MissingDropSet { set } => {
817                write!(f, "Static drop set {set} does not exist")
818            }
819            VmErrorKind::MissingGlobals { slot, name } => {
820                write!(f, "No storage has been configured for the static ")?;
821                fmt_global(f, *slot, name.as_deref())
822            }
823            VmErrorKind::BadGlobalSlot { slot, name } => {
824                write!(f, "The configured storage has no slot for the static ")?;
825                fmt_global(f, *slot, name.as_deref())
826            }
827            VmErrorKind::UninitializedGlobal { slot, name } => {
828                write!(f, "Reading uninitialized static ")?;
829                fmt_global(f, *slot, name.as_deref())
830            }
831            VmErrorKind::MissingRtti { hash } => {
832                write!(f, "Missing runtime information for type with hash `{hash}`")
833            }
834            VmErrorKind::BadArgumentCount { actual, expected } => {
835                write!(f, "Wrong number of arguments {actual}, expected {expected}",)
836            }
837            VmErrorKind::MaxValueDepth { max } => {
838                write!(f, "Value is nested too deeply to walk, limit is {max}")
839            }
840            VmErrorKind::MaxConstSize { max } => {
841                write!(f, "Value is too large to be a constant, limit is {max}")
842            }
843            VmErrorKind::MalformedConstValue => {
844                write!(f, "Constant value is not a tree")
845            }
846            VmErrorKind::MaxConstDepth { max } => {
847                write!(
848                    f,
849                    "Value is nested too deeply to be a constant, limit is {max}"
850                )
851            }
852            VmErrorKind::MaxExecutionDepth { max } => {
853                write!(f, "Executions are nested too deeply, limit is {max}")
854            }
855            VmErrorKind::BadEnvironmentCount { actual, expected } => write!(
856                f,
857                "Wrong environment size `{actual}`, expected `{expected}`",
858            ),
859            VmErrorKind::BadArgument { arg } => write!(f, "Bad argument #{arg}"),
860            VmErrorKind::UnsupportedIndexSet {
861                target,
862                index,
863                value,
864            } => write!(
865                f,
866                "The index set operation `{target}[{index}] = {value}` is not supported",
867            ),
868            VmErrorKind::UnsupportedIndexGet { target, index } => write!(
869                f,
870                "The index get operation `{target}[{index}]` is not supported",
871            ),
872            VmErrorKind::UnsupportedTupleIndexGet { target, index } => write!(
873                f,
874                "The tuple index get {index} operation is not supported on `{target}`",
875            ),
876            VmErrorKind::UnsupportedTupleIndexSet { target } => write!(
877                f,
878                "The tuple index set operation is not supported on `{target}`",
879            ),
880            VmErrorKind::UnsupportedObjectSlotIndexGet { target, field } => {
881                write!(f, "Field `{field}` not available on `{target}`")
882            }
883            VmErrorKind::UnsupportedObjectSlotIndexSet { target, field } => {
884                write!(f, "Field `{field}` not available to set on `{target}`")
885            }
886            VmErrorKind::UnsupportedIs { value, test_type } => {
887                write!(f, "Operation `{value} is {test_type}` is not supported")
888            }
889            VmErrorKind::UnsupportedAs { value } => write!(
890                f,
891                "Type `{value}` cannot be converted with `as`, which only converts between `i64`, `u64` and `f64`"
892            ),
893            // The type being converted to is not something the machine can name
894            // - all it has is a hash, which tells whoever wrote it nothing the
895            // source in front of them does not already say. What `as` can
896            // convert to is the half which is worth saying.
897            VmErrorKind::UnsupportedAsTarget { value } => write!(
898                f,
899                "Type `{value}` cannot be converted with `as` to that type, which only converts to `i64`, `u64` or `f64`"
900            ),
901            VmErrorKind::UnsupportedCallFn { actual } => write!(
902                f,
903                "Type `{actual}` cannot be called since it's not a function",
904            ),
905            VmErrorKind::ObjectIndexMissing { slot } => {
906                write!(f, "Missing index by static string slot `{slot}`")
907            }
908            VmErrorKind::MissingIndex { target } => {
909                write!(f, "Type `{target}` missing index")
910            }
911            VmErrorKind::MissingIndexInteger { target, index } => {
912                write!(f, "Type `{target}` missing integer index `{index}`")
913            }
914            VmErrorKind::MissingIndexKey { target } => {
915                write!(f, "Type `{target}` missing index")
916            }
917            VmErrorKind::OutOfRange { index, length } => write!(
918                f,
919                "Index out of bounds, the length is `{length}` but the index is `{index}`",
920            ),
921            VmErrorKind::UnsupportedTryOperand { actual } => {
922                write!(f, "Type `{actual}` is not supported as try operand")
923            }
924            VmErrorKind::UnsupportedIterRangeInclusive { start, end } => {
925                write!(f, "Cannot build an iterator out of {start}..={end}")
926            }
927            VmErrorKind::UnsupportedIterRangeFrom { start } => {
928                write!(f, "Cannot build an iterator out of {start}..")
929            }
930            VmErrorKind::UnsupportedIterRange { start, end } => {
931                write!(f, "Cannot build an iterator out of {start}..{end}")
932            }
933            VmErrorKind::UnsupportedIterNextOperand { actual } => {
934                write!(f, "Type `{actual}` is not supported as iter-next operand")
935            }
936            VmErrorKind::ExpectedType { expected, actual } => {
937                write!(f, "Expected type `{expected}` but found `{actual}`")
938            }
939            VmErrorKind::ExpectedAny { actual } => {
940                write!(f, "Expected `Any` type, but found `{actual}`")
941            }
942            VmErrorKind::ExpectedNumber { actual } => {
943                write!(f, "Expected number type, but found `{actual}`")
944            }
945            VmErrorKind::ExpectedEmpty { actual } => {
946                write!(f, "Expected empty, but found `{actual}`")
947            }
948            VmErrorKind::ExpectedTuple { actual } => {
949                write!(f, "Expected tuple, but found `{actual}`")
950            }
951            VmErrorKind::ExpectedStruct { actual } => {
952                write!(f, "Expected struct, but found `{actual}`")
953            }
954            VmErrorKind::MissingConstantConstructor { hash } => {
955                write!(f, "Missing constant constructor for type with hash {hash}")
956            }
957            VmErrorKind::ValueToIntegerCoercionError { from, to } => {
958                write!(f, "Failed to convert value `{from}` to integer `{to}`")
959            }
960            VmErrorKind::IntegerToValueCoercionError { from, to } => {
961                write!(f, "Failed to convert integer `{from}` to value `{to}`")
962            }
963            VmErrorKind::ExpectedTupleLength { actual, expected } => write!(
964                f,
965                "Expected a tuple of length `{expected}`, but found one with length `{actual}`",
966            ),
967            VmErrorKind::ExpectedVecLength { actual, expected } => write!(
968                f,
969                "Expected a vector of length `{expected}`, but found one with length `{actual}`",
970            ),
971            VmErrorKind::ConstNotSupported { actual } => {
972                write!(f, "Type `{actual}` can't be converted to a constant value")
973            }
974            VmErrorKind::MissingInterfaceEnvironment => {
975                write!(f, "Missing interface environment")
976            }
977            VmErrorKind::ExpectedExitedExecutionState { actual } => {
978                write!(f, "Expected exited execution state, but was {actual}")
979            }
980            VmErrorKind::GeneratorComplete => {
981                write!(f, "Cannot resume a generator that has completed")
982            }
983            VmErrorKind::FutureCompleted => write!(f, "Future already completed"),
984            VmErrorKind::MissingVariant { name } => write!(f, "No variant matching `{name}`"),
985            VmErrorKind::MissingField { target, field } => {
986                write!(f, "Missing field `{field}` on `{target}`")
987            }
988            VmErrorKind::MissingVariantName => {
989                write!(f, "missing variant name in runtime information")
990            }
991            VmErrorKind::MissingStructField { target, name } => write!(
992                f,
993                "missing dynamic field for struct field `{target}::{name}`",
994            ),
995            VmErrorKind::MissingTupleIndex { target, index } => write!(
996                f,
997                "missing dynamic index #{index} in tuple struct `{target}`",
998            ),
999            VmErrorKind::ExpectedVariant { actual } => {
1000                write!(f, "Expected an enum variant, but got `{actual}`")
1001            }
1002            VmErrorKind::UnsupportedObjectFieldGet { target } => write!(
1003                f,
1004                "The object field get operation is not supported on `{target}`",
1005            ),
1006            VmErrorKind::IllegalFloatComparison { lhs, rhs } => {
1007                write!(
1008                    f,
1009                    "Cannot perform a comparison of the floats {lhs} and {rhs}",
1010                )
1011            }
1012            VmErrorKind::IllegalFloatOperation { value } => {
1013                write!(f, "Cannot perform operation on float `{value}`")
1014            }
1015            VmErrorKind::MissingCallFrame => {
1016                write!(f, "Missing call frame for internal vm call")
1017            }
1018            VmErrorKind::IllegalFormat => {
1019                write!(f, "Value cannot be formatted")
1020            }
1021        }
1022    }
1023}
1024
1025impl From<Infallible> for VmErrorKind {
1026    #[inline]
1027    fn from(error: Infallible) -> Self {
1028        match error {}
1029    }
1030}
1031
1032impl<E> From<StoreError<E>> for VmErrorKind
1033where
1034    VmErrorKind: From<E>,
1035{
1036    #[inline]
1037    fn from(value: StoreError<E>) -> Self {
1038        match value.into_kind() {
1039            StoreErrorKind::Stack(error) => VmErrorKind::StackError { error },
1040            StoreErrorKind::Error(error) => VmErrorKind::from(error),
1041            StoreErrorKind::Alloc(error) => VmErrorKind::AllocError { error },
1042        }
1043    }
1044}
1045
1046impl From<RuntimeError> for VmErrorKind {
1047    #[inline]
1048    fn from(value: RuntimeError) -> Self {
1049        value.into_vm_error_kind()
1050    }
1051}
1052
1053impl From<AnySequenceTakeError> for VmErrorKind {
1054    #[inline]
1055    fn from(value: AnySequenceTakeError) -> Self {
1056        match value {
1057            AnySequenceTakeError::Access(error) => Self::from(error),
1058            AnySequenceTakeError::Alloc(error) => Self::from(error),
1059        }
1060    }
1061}
1062
1063impl From<AnyObjError> for VmErrorKind {
1064    #[inline]
1065    fn from(value: AnyObjError) -> Self {
1066        match value.into_kind() {
1067            AnyObjErrorKind::Alloc(error) => Self::from(error),
1068            AnyObjErrorKind::Cast(expected, actual) => VmErrorKind::ExpectedType {
1069                expected: TypeInfo::any_type_info(expected),
1070                actual,
1071            },
1072            AnyObjErrorKind::AccessError(error) => Self::from(error),
1073            AnyObjErrorKind::NotOwned(type_info) => VmErrorKind::NotOwned { type_info },
1074        }
1075    }
1076}
1077
1078impl From<AccessError> for VmErrorKind {
1079    #[inline]
1080    fn from(error: AccessError) -> Self {
1081        VmErrorKind::AccessError { error }
1082    }
1083}
1084
1085impl From<StackError> for VmErrorKind {
1086    #[inline]
1087    fn from(error: StackError) -> Self {
1088        VmErrorKind::StackError { error }
1089    }
1090}
1091
1092impl From<SliceError> for VmErrorKind {
1093    #[inline]
1094    fn from(error: SliceError) -> Self {
1095        VmErrorKind::SliceError { error }
1096    }
1097}
1098
1099impl From<BadInstruction> for VmErrorKind {
1100    #[inline]
1101    fn from(error: BadInstruction) -> Self {
1102        VmErrorKind::BadInstruction { error }
1103    }
1104}
1105
1106impl From<BadJump> for VmErrorKind {
1107    #[inline]
1108    fn from(error: BadJump) -> Self {
1109        VmErrorKind::BadJump { error }
1110    }
1111}
1112
1113impl From<DynArgsUsed> for VmErrorKind {
1114    #[inline]
1115    fn from(error: DynArgsUsed) -> Self {
1116        VmErrorKind::DynArgsUsed { error }
1117    }
1118}
1119
1120impl From<alloc::Error> for VmErrorKind {
1121    #[inline]
1122    fn from(error: alloc::Error) -> Self {
1123        VmErrorKind::AllocError { error }
1124    }
1125}
1126
1127impl From<alloc::alloc::AllocError> for VmErrorKind {
1128    #[inline]
1129    fn from(error: alloc::alloc::AllocError) -> Self {
1130        VmErrorKind::AllocError {
1131            error: error.into(),
1132        }
1133    }
1134}
1135
1136impl VmErrorKind {
1137    /// Bad argument.
1138    pub(crate) fn bad_argument(arg: usize) -> Self {
1139        Self::BadArgument { arg }
1140    }
1141
1142    /// Construct an expected error.
1143    pub(crate) fn expected<T>(actual: TypeInfo) -> Self
1144    where
1145        T: ?Sized + TypeOf,
1146    {
1147        Self::ExpectedType {
1148            expected: T::type_info(),
1149            actual,
1150        }
1151    }
1152}
1153
1154#[derive(Debug, Clone, Copy)]
1155#[cfg_attr(test, derive(PartialEq))]
1156enum VmIntegerReprKind {
1157    Signed(i128),
1158    Unsigned(u128),
1159    Isize(isize),
1160    Usize(usize),
1161}
1162
1163/// A type-erased integer representation.
1164#[derive(Clone)]
1165#[cfg_attr(test, derive(PartialEq))]
1166pub(crate) struct VmIntegerRepr {
1167    kind: VmIntegerReprKind,
1168}
1169
1170impl VmIntegerRepr {
1171    #[inline]
1172    fn new(kind: VmIntegerReprKind) -> Self {
1173        Self { kind }
1174    }
1175}
1176
1177macro_rules! impl_from {
1178    ($($variant:ident => [$($ty:ty),* $(,)?]),* $(,)?) => {
1179        $($(
1180            impl From<$ty> for VmIntegerRepr {
1181                #[inline]
1182                fn from(value: $ty) -> Self {
1183                    Self::new(VmIntegerReprKind::$variant(From::from(value)))
1184                }
1185            }
1186        )*)*
1187    };
1188}
1189
1190impl_from! {
1191    Signed => [i8, i16, i32, i64, i128],
1192    Unsigned => [u8, u16, u32, u64, u128],
1193    Isize => [isize],
1194    Usize => [usize],
1195}
1196
1197impl fmt::Display for VmIntegerRepr {
1198    #[inline]
1199    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1200        match &self.kind {
1201            VmIntegerReprKind::Signed(value) => value.fmt(f),
1202            VmIntegerReprKind::Unsigned(value) => value.fmt(f),
1203            VmIntegerReprKind::Isize(value) => value.fmt(f),
1204            VmIntegerReprKind::Usize(value) => value.fmt(f),
1205        }
1206    }
1207}
1208
1209impl fmt::Debug for VmIntegerRepr {
1210    #[inline]
1211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1212        self.kind.fmt(f)
1213    }
1214}
1215
1216/// Format a static item for diagnostics, using its name if debug information
1217/// was available and falling back to its slot if it wasn't.
1218fn fmt_global(f: &mut fmt::Formatter<'_>, slot: usize, name: Option<&Item>) -> fmt::Result {
1219    match name {
1220        Some(name) => write!(f, "`{name}` (slot {slot})"),
1221        None => write!(f, "in slot {slot}"),
1222    }
1223}