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