1use std::any::Any;
2use std::backtrace::Backtrace;
3use std::borrow::Cow;
4use std::{convert, fmt, mem, ops};
5
6use either::Either;
7use rustc_abi::{Align, Size, VariantIdx, WrappingRange};
8use rustc_data_structures::sync::Lock;
9use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg};
10use rustc_macros::{HashStable, TyDecodable, TyEncodable};
11use rustc_session::CtfeBacktrace;
12use rustc_span::def_id::DefId;
13use rustc_span::{DUMMY_SP, Span, Symbol};
14
15use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar};
16use crate::error;
17use crate::mir::{ConstAlloc, ConstValue};
18use crate::ty::{self, Mutability, Ty, TyCtxt, ValTree, layout, tls};
19
20#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
21pub enum ErrorHandled {
22    Reported(ReportedErrorInfo, Span),
25    TooGeneric(Span),
28}
29
30impl From<ReportedErrorInfo> for ErrorHandled {
31    #[inline]
32    fn from(error: ReportedErrorInfo) -> ErrorHandled {
33        ErrorHandled::Reported(error, DUMMY_SP)
34    }
35}
36
37impl ErrorHandled {
38    pub(crate) fn with_span(self, span: Span) -> Self {
39        match self {
40            ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
41            ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
42        }
43    }
44
45    pub fn emit_note(&self, tcx: TyCtxt<'_>) {
46        match self {
47            &ErrorHandled::Reported(err, span) => {
48                if !err.allowed_in_infallible && !span.is_dummy() {
49                    tcx.dcx().emit_note(error::ErroneousConstant { span });
50                }
51            }
52            &ErrorHandled::TooGeneric(_) => {}
53        }
54    }
55}
56
57#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
58pub struct ReportedErrorInfo {
59    error: ErrorGuaranteed,
60    allowed_in_infallible: bool,
63}
64
65impl ReportedErrorInfo {
66    #[inline]
67    pub fn const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
68        ReportedErrorInfo { allowed_in_infallible: false, error }
69    }
70
71    #[inline]
74    pub fn non_const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
75        ReportedErrorInfo { allowed_in_infallible: true, error }
76    }
77
78    #[inline]
81    pub fn allowed_in_infallible(error: ErrorGuaranteed) -> ReportedErrorInfo {
82        ReportedErrorInfo { allowed_in_infallible: true, error }
83    }
84
85    pub fn is_allowed_in_infallible(&self) -> bool {
86        self.allowed_in_infallible
87    }
88}
89
90impl From<ReportedErrorInfo> for ErrorGuaranteed {
91    #[inline]
92    fn from(val: ReportedErrorInfo) -> Self {
93        val.error
94    }
95}
96
97#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
100pub enum ValTreeCreationError<'tcx> {
101    NodesOverflow,
103    InvalidConst,
105    NonSupportedType(Ty<'tcx>),
107    ErrorHandled(ErrorHandled),
109}
110
111impl<'tcx> From<ErrorHandled> for ValTreeCreationError<'tcx> {
112    fn from(err: ErrorHandled) -> Self {
113        ValTreeCreationError::ErrorHandled(err)
114    }
115}
116
117impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
118    fn from(err: InterpErrorInfo<'tcx>) -> Self {
119        let (_kind, backtrace) = err.into_parts();
123        backtrace.print_backtrace();
124        ValTreeCreationError::InvalidConst
125    }
126}
127
128impl<'tcx> ValTreeCreationError<'tcx> {
129    pub(crate) fn with_span(self, span: Span) -> Self {
130        use ValTreeCreationError::*;
131        match self {
132            ErrorHandled(handled) => ErrorHandled(handled.with_span(span)),
133            other => other,
134        }
135    }
136}
137
138pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
139pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
140pub type EvalToConstValueResult<'tcx> = Result<ConstValue, ErrorHandled>;
141pub type EvalToValTreeResult<'tcx> = Result<ValTree<'tcx>, ValTreeCreationError<'tcx>>;
142
143#[cfg(target_pointer_width = "64")]
144rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8);
145
146#[derive(Debug)]
156pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
157
158#[derive(Debug)]
159struct InterpErrorInfoInner<'tcx> {
160    kind: InterpErrorKind<'tcx>,
161    backtrace: InterpErrorBacktrace,
162}
163
164#[derive(Debug)]
165pub struct InterpErrorBacktrace {
166    backtrace: Option<Box<Backtrace>>,
167}
168
169impl InterpErrorBacktrace {
170    pub fn new() -> InterpErrorBacktrace {
171        let capture_backtrace = tls::with_opt(|tcx| {
172            if let Some(tcx) = tcx {
173                *Lock::borrow(&tcx.sess.ctfe_backtrace)
174            } else {
175                CtfeBacktrace::Disabled
176            }
177        });
178
179        let backtrace = match capture_backtrace {
180            CtfeBacktrace::Disabled => None,
181            CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
182            CtfeBacktrace::Immediate => {
183                let backtrace = Backtrace::force_capture();
185                print_backtrace(&backtrace);
186                None
187            }
188        };
189
190        InterpErrorBacktrace { backtrace }
191    }
192
193    pub fn print_backtrace(&self) {
194        if let Some(backtrace) = self.backtrace.as_ref() {
195            print_backtrace(backtrace);
196        }
197    }
198}
199
200impl<'tcx> InterpErrorInfo<'tcx> {
201    pub fn into_parts(self) -> (InterpErrorKind<'tcx>, InterpErrorBacktrace) {
202        let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self;
203        (kind, backtrace)
204    }
205
206    pub fn into_kind(self) -> InterpErrorKind<'tcx> {
207        self.0.kind
208    }
209
210    pub fn from_parts(kind: InterpErrorKind<'tcx>, backtrace: InterpErrorBacktrace) -> Self {
211        Self(Box::new(InterpErrorInfoInner { kind, backtrace }))
212    }
213
214    #[inline]
215    pub fn kind(&self) -> &InterpErrorKind<'tcx> {
216        &self.0.kind
217    }
218}
219
220fn print_backtrace(backtrace: &Backtrace) {
221    eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}");
222}
223
224impl From<ErrorHandled> for InterpErrorInfo<'_> {
225    fn from(err: ErrorHandled) -> Self {
226        InterpErrorKind::InvalidProgram(match err {
227            ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
228            ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
229        })
230        .into()
231    }
232}
233
234impl<'tcx> From<InterpErrorKind<'tcx>> for InterpErrorInfo<'tcx> {
235    fn from(kind: InterpErrorKind<'tcx>) -> Self {
236        InterpErrorInfo(Box::new(InterpErrorInfoInner {
237            kind,
238            backtrace: InterpErrorBacktrace::new(),
239        }))
240    }
241}
242
243#[derive(Debug)]
248pub enum InvalidProgramInfo<'tcx> {
249    TooGeneric,
251    AlreadyReported(ReportedErrorInfo),
253    Layout(layout::LayoutError<'tcx>),
255}
256
257#[derive(Debug, Copy, Clone)]
259pub enum CheckInAllocMsg {
260    MemoryAccess,
262    InboundsPointerArithmetic,
264    Dereferenceable,
266}
267
268#[derive(Debug, Copy, Clone)]
270pub enum CheckAlignMsg {
271    AccessedPtr,
273    BasedOn,
275}
276
277#[derive(Debug, Copy, Clone)]
278pub enum InvalidMetaKind {
279    SliceTooBig,
281    TooBig,
283}
284
285impl IntoDiagArg for InvalidMetaKind {
286    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
287        DiagArgValue::Str(Cow::Borrowed(match self {
288            InvalidMetaKind::SliceTooBig => "slice_too_big",
289            InvalidMetaKind::TooBig => "too_big",
290        }))
291    }
292}
293
294#[derive(Debug, Clone, Copy)]
296pub struct BadBytesAccess {
297    pub access: AllocRange,
299    pub bad: AllocRange,
301}
302
303#[derive(Debug)]
305pub struct ScalarSizeMismatch {
306    pub target_size: u64,
307    pub data_size: u64,
308}
309
310#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
312pub struct Misalignment {
313    pub has: Align,
314    pub required: Align,
315}
316
317macro_rules! impl_into_diag_arg_through_debug {
318    ($($ty:ty),*$(,)?) => {$(
319        impl IntoDiagArg for $ty {
320            fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
321                DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
322            }
323        }
324    )*}
325}
326
327impl_into_diag_arg_through_debug! {
329    AllocId,
330    Pointer<AllocId>,
331    AllocRange,
332}
333
334#[derive(Debug)]
336pub enum UndefinedBehaviorInfo<'tcx> {
337    Ub(String),
339    Custom(crate::error::CustomSubdiagnostic<'tcx>),
343    ValidationError(ValidationErrorInfo<'tcx>),
345
346    Unreachable,
348    BoundsCheckFailed { len: u64, index: u64 },
350    DivisionByZero,
352    RemainderByZero,
354    DivisionOverflow,
356    RemainderOverflow,
358    PointerArithOverflow,
360    ArithOverflow { intrinsic: Symbol },
362    ShiftOverflow { intrinsic: Symbol, shift_amount: Either<u128, i128> },
364    InvalidMeta(InvalidMetaKind),
366    UnterminatedCString(Pointer<AllocId>),
368    PointerUseAfterFree(AllocId, CheckInAllocMsg),
370    PointerOutOfBounds {
372        alloc_id: AllocId,
373        alloc_size: Size,
374        ptr_offset: i64,
375        inbounds_size: i64,
377        msg: CheckInAllocMsg,
378    },
379    DanglingIntPointer {
381        addr: u64,
382        inbounds_size: i64,
385        msg: CheckInAllocMsg,
386    },
387    AlignmentCheckFailed(Misalignment, CheckAlignMsg),
389    WriteToReadOnly(AllocId),
391    DerefFunctionPointer(AllocId),
393    DerefVTablePointer(AllocId),
395    DerefTypeIdPointer(AllocId),
397    InvalidBool(u8),
399    InvalidChar(u32),
401    InvalidTag(Scalar<AllocId>),
403    InvalidFunctionPointer(Pointer<AllocId>),
405    InvalidVTablePointer(Pointer<AllocId>),
407    InvalidVTableTrait {
409        vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
411        expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
413    },
414    InvalidStr(std::str::Utf8Error),
416    InvalidUninitBytes(Option<(AllocId, BadBytesAccess)>),
418    DeadLocal,
420    ScalarSizeMismatch(ScalarSizeMismatch),
422    UninhabitedEnumVariantWritten(VariantIdx),
424    UninhabitedEnumVariantRead(Option<VariantIdx>),
426    InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
428    AbiMismatchArgument {
430        arg_idx: usize,
432        caller_ty: Ty<'tcx>,
433        callee_ty: Ty<'tcx>,
434    },
435    AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
437}
438
439#[derive(Debug, Clone, Copy)]
440pub enum PointerKind {
441    Ref(Mutability),
442    Box,
443}
444
445impl IntoDiagArg for PointerKind {
446    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
447        DiagArgValue::Str(
448            match self {
449                Self::Ref(_) => "ref",
450                Self::Box => "box",
451            }
452            .into(),
453        )
454    }
455}
456
457#[derive(Debug)]
458pub struct ValidationErrorInfo<'tcx> {
459    pub path: Option<String>,
460    pub kind: ValidationErrorKind<'tcx>,
461}
462
463#[derive(Debug)]
464pub enum ExpectedKind {
465    Reference,
466    Box,
467    RawPtr,
468    InitScalar,
469    Bool,
470    Char,
471    Float,
472    Int,
473    FnPtr,
474    EnumTag,
475    Str,
476}
477
478impl From<PointerKind> for ExpectedKind {
479    fn from(x: PointerKind) -> ExpectedKind {
480        match x {
481            PointerKind::Box => ExpectedKind::Box,
482            PointerKind::Ref(_) => ExpectedKind::Reference,
483        }
484    }
485}
486
487#[derive(Debug)]
488pub enum ValidationErrorKind<'tcx> {
489    PointerAsInt {
490        expected: ExpectedKind,
491    },
492    PartialPointer,
493    PtrToUninhabited {
494        ptr_kind: PointerKind,
495        ty: Ty<'tcx>,
496    },
497    MutableRefToImmutable,
498    UnsafeCellInImmutable,
499    MutableRefInConst,
500    NullFnPtr,
501    NeverVal,
502    NullablePtrOutOfRange {
503        range: WrappingRange,
504        max_value: u128,
505    },
506    PtrOutOfRange {
507        range: WrappingRange,
508        max_value: u128,
509    },
510    OutOfRange {
511        value: String,
512        range: WrappingRange,
513        max_value: u128,
514    },
515    UninhabitedVal {
516        ty: Ty<'tcx>,
517    },
518    InvalidEnumTag {
519        value: String,
520    },
521    UninhabitedEnumVariant,
522    Uninit {
523        expected: ExpectedKind,
524    },
525    InvalidVTablePtr {
526        value: String,
527    },
528    InvalidMetaWrongTrait {
529        vtable_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
531        expected_dyn_type: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
533    },
534    InvalidMetaSliceTooLarge {
535        ptr_kind: PointerKind,
536    },
537    InvalidMetaTooLarge {
538        ptr_kind: PointerKind,
539    },
540    UnalignedPtr {
541        ptr_kind: PointerKind,
542        required_bytes: u64,
543        found_bytes: u64,
544    },
545    NullPtr {
546        ptr_kind: PointerKind,
547    },
548    DanglingPtrNoProvenance {
549        ptr_kind: PointerKind,
550        pointer: String,
551    },
552    DanglingPtrOutOfBounds {
553        ptr_kind: PointerKind,
554    },
555    DanglingPtrUseAfterFree {
556        ptr_kind: PointerKind,
557    },
558    InvalidBool {
559        value: String,
560    },
561    InvalidChar {
562        value: String,
563    },
564    InvalidFnPtr {
565        value: String,
566    },
567}
568
569#[derive(Debug)]
574pub enum UnsupportedOpInfo {
575    Unsupported(String),
578    UnsizedLocal,
580    ExternTypeField,
582    ReadPartialPointer(Pointer<AllocId>),
588    ReadPointerAsInt(Option<(AllocId, BadBytesAccess)>),
590    ThreadLocalStatic(DefId),
592    ExternStatic(DefId),
594}
595
596#[derive(Debug)]
599pub enum ResourceExhaustionInfo {
600    StackFrameLimitReached,
602    MemoryExhausted,
604    AddressSpaceFull,
606    Interrupted,
608}
609
610pub trait MachineStopType: Any + fmt::Debug + Send {
612    fn diagnostic_message(&self) -> DiagMessage;
614    fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue));
617}
618
619impl dyn MachineStopType {
620    #[inline(always)]
621    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
622        let x: &dyn Any = self;
623        x.downcast_ref()
624    }
625}
626
627#[derive(Debug)]
628pub enum InterpErrorKind<'tcx> {
629    UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
631    Unsupported(UnsupportedOpInfo),
634    InvalidProgram(InvalidProgramInfo<'tcx>),
636    ResourceExhaustion(ResourceExhaustionInfo),
639    MachineStop(Box<dyn MachineStopType>),
642}
643
644impl InterpErrorKind<'_> {
645    pub fn formatted_string(&self) -> bool {
649        matches!(
650            self,
651            InterpErrorKind::Unsupported(UnsupportedOpInfo::Unsupported(_))
652                | InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. })
653                | InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
654        )
655    }
656}
657
658#[macro_export]
660macro_rules! err_unsup {
661    ($($tt:tt)*) => {
662        $crate::mir::interpret::InterpErrorKind::Unsupported(
663            $crate::mir::interpret::UnsupportedOpInfo::$($tt)*
664        )
665    };
666}
667
668#[macro_export]
669macro_rules! err_unsup_format {
670    ($($tt:tt)*) => { $crate::err_unsup!(Unsupported(format!($($tt)*))) };
671}
672
673#[macro_export]
674macro_rules! err_inval {
675    ($($tt:tt)*) => {
676        $crate::mir::interpret::InterpErrorKind::InvalidProgram(
677            $crate::mir::interpret::InvalidProgramInfo::$($tt)*
678        )
679    };
680}
681
682#[macro_export]
683macro_rules! err_ub {
684    ($($tt:tt)*) => {
685        $crate::mir::interpret::InterpErrorKind::UndefinedBehavior(
686            $crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
687        )
688    };
689}
690
691#[macro_export]
692macro_rules! err_ub_format {
693    ($($tt:tt)*) => { $crate::err_ub!(Ub(format!($($tt)*))) };
694}
695
696#[macro_export]
697macro_rules! err_ub_custom {
698    ($msg:expr $(, $($name:ident = $value:expr),* $(,)?)?) => {{
699        $(
700            let ($($name,)*) = ($($value,)*);
701        )?
702        $crate::err_ub!(Custom(
703            $crate::error::CustomSubdiagnostic {
704                msg: || $msg,
705                add_args: Box::new(move |mut set_arg| {
706                    $($(
707                        set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name, &mut None));
708                    )*)?
709                })
710            }
711        ))
712    }};
713}
714
715#[macro_export]
716macro_rules! err_exhaust {
717    ($($tt:tt)*) => {
718        $crate::mir::interpret::InterpErrorKind::ResourceExhaustion(
719            $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
720        )
721    };
722}
723
724#[macro_export]
725macro_rules! err_machine_stop {
726    ($($tt:tt)*) => {
727        $crate::mir::interpret::InterpErrorKind::MachineStop(Box::new($($tt)*))
728    };
729}
730
731#[macro_export]
733macro_rules! throw_unsup {
734    ($($tt:tt)*) => { do yeet $crate::err_unsup!($($tt)*) };
735}
736
737#[macro_export]
738macro_rules! throw_unsup_format {
739    ($($tt:tt)*) => { do yeet $crate::err_unsup_format!($($tt)*) };
740}
741
742#[macro_export]
743macro_rules! throw_inval {
744    ($($tt:tt)*) => { do yeet $crate::err_inval!($($tt)*) };
745}
746
747#[macro_export]
748macro_rules! throw_ub {
749    ($($tt:tt)*) => { do yeet $crate::err_ub!($($tt)*) };
750}
751
752#[macro_export]
753macro_rules! throw_ub_format {
754    ($($tt:tt)*) => { do yeet $crate::err_ub_format!($($tt)*) };
755}
756
757#[macro_export]
758macro_rules! throw_ub_custom {
759    ($($tt:tt)*) => { do yeet $crate::err_ub_custom!($($tt)*) };
760}
761
762#[macro_export]
763macro_rules! throw_exhaust {
764    ($($tt:tt)*) => { do yeet $crate::err_exhaust!($($tt)*) };
765}
766
767#[macro_export]
768macro_rules! throw_machine_stop {
769    ($($tt:tt)*) => { do yeet $crate::err_machine_stop!($($tt)*) };
770}
771
772#[derive(Debug)]
774struct Guard;
775
776impl Drop for Guard {
777    fn drop(&mut self) {
778        if !std::thread::panicking() {
780            panic!(
781                "an interpreter error got improperly discarded; use `discard_err()` if this is intentional"
782            );
783        }
784    }
785}
786
787#[derive(Debug)]
792#[must_use]
793pub struct InterpResult<'tcx, T = ()> {
794    res: Result<T, InterpErrorInfo<'tcx>>,
795    guard: Guard,
796}
797
798impl<'tcx, T> ops::Try for InterpResult<'tcx, T> {
799    type Output = T;
800    type Residual = InterpResult<'tcx, convert::Infallible>;
801
802    #[inline]
803    fn from_output(output: Self::Output) -> Self {
804        InterpResult::new(Ok(output))
805    }
806
807    #[inline]
808    fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> {
809        match self.disarm() {
810            Ok(v) => ops::ControlFlow::Continue(v),
811            Err(e) => ops::ControlFlow::Break(InterpResult::new(Err(e))),
812        }
813    }
814}
815
816impl<'tcx, T> ops::Residual<T> for InterpResult<'tcx, convert::Infallible> {
817    type TryType = InterpResult<'tcx, T>;
818}
819
820impl<'tcx, T> ops::FromResidual for InterpResult<'tcx, T> {
821    #[inline]
822    #[track_caller]
823    fn from_residual(residual: InterpResult<'tcx, convert::Infallible>) -> Self {
824        match residual.disarm() {
825            Err(e) => Self::new(Err(e)),
826        }
827    }
828}
829
830impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult<'tcx, T> {
832    #[inline]
833    fn from_residual(ops::Yeet(e): ops::Yeet<InterpErrorKind<'tcx>>) -> Self {
834        Self::new(Err(e.into()))
835    }
836}
837
838impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> ops::FromResidual<Result<convert::Infallible, E>>
841    for InterpResult<'tcx, T>
842{
843    #[inline]
844    fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
845        match residual {
846            Err(e) => Self::new(Err(e.into())),
847        }
848    }
849}
850
851impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> From<Result<T, E>> for InterpResult<'tcx, T> {
852    #[inline]
853    fn from(value: Result<T, E>) -> Self {
854        Self::new(value.map_err(|e| e.into()))
855    }
856}
857
858impl<'tcx, T, V: FromIterator<T>> FromIterator<InterpResult<'tcx, T>> for InterpResult<'tcx, V> {
859    fn from_iter<I: IntoIterator<Item = InterpResult<'tcx, T>>>(iter: I) -> Self {
860        Self::new(iter.into_iter().map(|x| x.disarm()).collect())
861    }
862}
863
864impl<'tcx, T> InterpResult<'tcx, T> {
865    #[inline(always)]
866    fn new(res: Result<T, InterpErrorInfo<'tcx>>) -> Self {
867        Self { res, guard: Guard }
868    }
869
870    #[inline(always)]
871    fn disarm(self) -> Result<T, InterpErrorInfo<'tcx>> {
872        mem::forget(self.guard);
873        self.res
874    }
875
876    #[inline]
878    pub fn discard_err(self) -> Option<T> {
879        self.disarm().ok()
880    }
881
882    #[inline]
885    pub fn report_err(self) -> Result<T, InterpErrorInfo<'tcx>> {
886        self.disarm()
887    }
888
889    #[inline]
890    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> {
891        InterpResult::new(self.disarm().map(f))
892    }
893
894    #[inline]
895    pub fn map_err_info(
896        self,
897        f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>,
898    ) -> InterpResult<'tcx, T> {
899        InterpResult::new(self.disarm().map_err(f))
900    }
901
902    #[inline]
903    pub fn map_err_kind(
904        self,
905        f: impl FnOnce(InterpErrorKind<'tcx>) -> InterpErrorKind<'tcx>,
906    ) -> InterpResult<'tcx, T> {
907        InterpResult::new(self.disarm().map_err(|mut e| {
908            e.0.kind = f(e.0.kind);
909            e
910        }))
911    }
912
913    #[inline]
914    pub fn inspect_err_kind(self, f: impl FnOnce(&InterpErrorKind<'tcx>)) -> InterpResult<'tcx, T> {
915        InterpResult::new(self.disarm().inspect_err(|e| f(&e.0.kind)))
916    }
917
918    #[inline]
919    #[track_caller]
920    pub fn unwrap(self) -> T {
921        self.disarm().unwrap()
922    }
923
924    #[inline]
925    #[track_caller]
926    pub fn unwrap_or_else(self, f: impl FnOnce(InterpErrorInfo<'tcx>) -> T) -> T {
927        self.disarm().unwrap_or_else(f)
928    }
929
930    #[inline]
931    #[track_caller]
932    pub fn expect(self, msg: &str) -> T {
933        self.disarm().expect(msg)
934    }
935
936    #[inline]
937    pub fn and_then<U>(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> {
938        InterpResult::new(self.disarm().and_then(|t| f(t).disarm()))
939    }
940
941    #[inline]
946    pub fn and<U>(self, other: InterpResult<'tcx, U>) -> InterpResult<'tcx, (T, U)> {
947        match self.disarm() {
948            Ok(t) => interp_ok((t, other?)),
949            Err(e) => {
950                drop(other.disarm());
952                InterpResult::new(Err(e))
954            }
955        }
956    }
957}
958
959#[inline(always)]
960pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> {
961    InterpResult::new(Ok(x))
962}