Skip to main content

hir_ty/mir/
eval.rs

1//! This module provides a MIR interpreter, which is used in const eval.
2
3use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range};
4
5use base_db::{Crate, target::TargetLoadError};
6use either::Either;
7use hir_def::{
8    AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId,
9    VariantId,
10    expr_store::{Body, ExpressionStore, HygieneId},
11    item_tree::FieldsShape,
12    lang_item::LangItems,
13    layout::{TagEncoding, Variants},
14    resolver::{HasResolver, ValueNs},
15    signatures::{
16        EnumSignature, FunctionSignature, StaticFlags, StaticSignature, StructFlags,
17        StructSignature, TraitSignature,
18    },
19};
20use hir_expand::{InFile, mod_path::path};
21use la_arena::ArenaMap;
22use macros::GenericTypeVisitable;
23use rustc_abi::{Size, TargetDataLayout};
24use rustc_apfloat::{
25    Float,
26    ieee::{Half as f16, Quad as f128},
27};
28use rustc_ast_ir::Mutability;
29use rustc_hash::{FxHashMap, FxHashSet};
30use rustc_type_ir::{
31    AliasTyKind,
32    inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},
33};
34use salsa::SalsaValue;
35use span::FileId;
36use stdx::never;
37use syntax::{SyntaxNodePtr, TextRange};
38use triomphe::Arc;
39
40use crate::{
41    CallableDefId, ComplexMemoryMap, InferBodyId, InferenceResult, MemoryMap, ParamEnvAndCrate,
42    consteval::{self, ConstEvalError, try_const_usize},
43    db::{GeneralConstId, HirDatabase, InternedClosureId},
44    display::{ClosureStyle, DisplayTarget, HirDisplay},
45    infer::PointerCast,
46    layout::{Layout, LayoutError, RustcEnumVariantIdx},
47    method_resolution::{is_dyn_method, lookup_impl_const},
48    next_solver::{
49        AliasTy, Allocation, AllocationData, Const, ConstKind, DbInterner, ErrorGuaranteed,
50        GenericArgs, Region, StoredTy, Ty, TyKind, TypingMode, UnevaluatedConst, ValTree,
51        infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
52        obligation_ctxt::ObligationCtxt,
53    },
54    traits::FnTrait,
55    utils::detect_variant_from_bytes,
56};
57
58use super::{
59    AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan,
60    Operand, OperandKind, Place, PlaceElem, PlaceTy, ProjectionElem, Rvalue, StatementKind,
61    StoredPlace, TerminatorKind, UnOp, return_slot,
62};
63
64mod shim;
65#[cfg(test)]
66mod tests;
67
68macro_rules! from_bytes {
69    ($ty:tt, $value:expr) => {
70        ($ty::from_le_bytes(match ($value).try_into() {
71            Ok(it) => it,
72            Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $ty).into())),
73        }))
74    };
75    ($apfloat:tt, $bits:tt, $value:expr) => {
76        // FIXME(#17451): Switch to builtin `f16` and `f128` once they are stable.
77        $apfloat::from_bits($bits::from_le_bytes(match ($value).try_into() {
78            Ok(it) => it,
79            Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $apfloat).into())),
80        }).into())
81    };
82}
83use from_bytes;
84
85macro_rules! not_supported {
86    ($it: expr) => {
87        return Err($crate::mir::eval::MirEvalError::NotSupported(format!($it)))
88    };
89}
90use not_supported;
91
92#[derive(Debug, Default, Clone, PartialEq, Eq, GenericTypeVisitable)]
93pub struct VTableMap<'db> {
94    ty_to_id: FxHashMap<Ty<'db>, usize>,
95    id_to_ty: Vec<Ty<'db>>,
96}
97
98impl<'db> VTableMap<'db> {
99    const OFFSET: usize = 1000; // We should add some offset to ids to make 0 (null) an invalid id.
100
101    fn id(&mut self, ty: Ty<'db>) -> usize {
102        if let Some(it) = self.ty_to_id.get(&ty) {
103            return *it;
104        }
105        let id = self.id_to_ty.len() + VTableMap::OFFSET;
106        self.id_to_ty.push(ty);
107        self.ty_to_id.insert(ty, id);
108        id
109    }
110
111    pub(crate) fn ty(&self, id: usize) -> Result<'db, Ty<'db>> {
112        id.checked_sub(VTableMap::OFFSET)
113            .and_then(|id| self.id_to_ty.get(id).copied())
114            .ok_or(MirEvalError::InvalidVTableId(id))
115    }
116
117    fn ty_of_bytes(&self, bytes: &[u8]) -> Result<'db, Ty<'db>> {
118        let id = from_bytes!(usize, bytes);
119        self.ty(id)
120    }
121
122    pub fn shrink_to_fit(&mut self) {
123        self.id_to_ty.shrink_to_fit();
124        self.ty_to_id.shrink_to_fit();
125    }
126
127    fn is_empty(&self) -> bool {
128        self.id_to_ty.is_empty() && self.ty_to_id.is_empty()
129    }
130}
131
132#[derive(Debug, Default, Clone, PartialEq, Eq)]
133struct TlsData {
134    keys: Vec<u128>,
135}
136
137impl TlsData {
138    fn create_key(&mut self) -> usize {
139        self.keys.push(0);
140        self.keys.len() - 1
141    }
142
143    fn get_key(&mut self, key: usize) -> Result<'static, u128> {
144        let r = self.keys.get(key).ok_or_else(|| {
145            MirEvalError::UndefinedBehavior(format!("Getting invalid tls key {key}"))
146        })?;
147        Ok(*r)
148    }
149
150    fn set_key(&mut self, key: usize, value: u128) -> Result<'static, ()> {
151        let r = self.keys.get_mut(key).ok_or_else(|| {
152            MirEvalError::UndefinedBehavior(format!("Setting invalid tls key {key}"))
153        })?;
154        *r = value;
155        Ok(())
156    }
157}
158
159struct StackFrame<'a, 'db> {
160    locals: Locals<'a, 'db>,
161    destination: Option<BasicBlockId>,
162    prev_stack_ptr: usize,
163    span: (MirSpan, InferBodyId<'db>),
164}
165
166#[derive(Clone)]
167enum MirOrDynIndex<'db> {
168    Mir(&'db MirBody<'db>),
169    Dyn(usize),
170}
171
172pub struct Evaluator<'a, 'db> {
173    db: &'db dyn HirDatabase,
174    param_env: ParamEnvAndCrate<'db>,
175    target_data_layout: &'db TargetDataLayout,
176    stack: Vec<u8>,
177    heap: Vec<u8>,
178    code_stack: Vec<StackFrame<'a, 'db>>,
179    /// Stores the global location of the statics. We const evaluate every static first time we need it
180    /// and see it's missing, then we add it to this to reuse.
181    static_locations: FxHashMap<StaticId, Address>,
182    /// We don't really have function pointers, i.e. pointers to some assembly instructions that we can run. Instead, we
183    /// store the type as an interned id in place of function and vtable pointers, and we recover back the type at the
184    /// time of use.
185    vtable_map: VTableMap<'db>,
186    thread_local_storage: TlsData,
187    random_state: oorandom::Rand64,
188    stdout: Vec<u8>,
189    stderr: Vec<u8>,
190    layout_cache: RefCell<FxHashMap<Ty<'db>, Arc<Layout>>>,
191    projected_ty_cache: RefCell<FxHashMap<(PlaceTy<'db>, PlaceElem), PlaceTy<'db>>>,
192    not_special_fn_cache: RefCell<FxHashSet<FunctionId>>,
193    mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, GenericArgs<'db>), MirOrDynIndex<'db>>>,
194    /// Constantly dropping and creating `Locals` is very costly. We store
195    /// old locals that we normally want to drop here, to reuse their allocations
196    /// later.
197    unused_locals_store: RefCell<FxHashMap<InferBodyId<'db>, Vec<Locals<'a, 'db>>>>,
198    cached_ptr_size: usize,
199    cached_fn_trait_func: Option<FunctionId>,
200    cached_fn_mut_trait_func: Option<FunctionId>,
201    cached_fn_once_trait_func: Option<FunctionId>,
202    crate_id: Crate,
203    // FIXME: This is a workaround, see the comment on `interpret_mir`
204    assert_placeholder_ty_is_unused: bool,
205    /// A general limit on execution, to prevent non terminating programs from breaking r-a main process
206    execution_limit: usize,
207    /// An additional limit on stack depth, to prevent stack overflow
208    stack_depth_limit: usize,
209    /// Maximum count of bytes that heap and stack can grow
210    memory_limit: usize,
211    infcx: InferCtxt<'db>,
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
215enum Address {
216    Stack(usize),
217    Heap(usize),
218    Invalid(usize),
219}
220
221use Address::*;
222
223#[derive(Debug, Clone, Copy)]
224struct Interval {
225    addr: Address,
226    size: usize,
227}
228
229#[derive(Debug, Clone)]
230struct IntervalAndTy<'db> {
231    interval: Interval,
232    ty: Ty<'db>,
233}
234
235impl Interval {
236    fn new(addr: Address, size: usize) -> Self {
237        Self { addr, size }
238    }
239
240    fn get<'b, 'a, 'db>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {
241        memory.read_memory(self.addr, self.size)
242    }
243
244    fn write_from_bytes<'a, 'db>(
245        &self,
246        memory: &mut Evaluator<'a, 'db>,
247        bytes: &[u8],
248    ) -> Result<'db, ()> {
249        memory.write_memory(self.addr, bytes)
250    }
251
252    fn write_from_interval<'a, 'db>(
253        &self,
254        memory: &mut Evaluator<'a, 'db>,
255        interval: Interval,
256    ) -> Result<'db, ()> {
257        memory.copy_from_interval(self.addr, interval)
258    }
259
260    fn slice(self, range: Range<usize>) -> Interval {
261        Interval { addr: self.addr.offset(range.start), size: range.len() }
262    }
263}
264
265impl<'db> IntervalAndTy<'db> {
266    fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {
267        memory.read_memory(self.interval.addr, self.interval.size)
268    }
269
270    fn new<'a>(
271        addr: Address,
272        ty: Ty<'db>,
273        evaluator: &Evaluator<'a, 'db>,
274        locals: &Locals<'a, 'db>,
275    ) -> Result<'db, IntervalAndTy<'db>> {
276        let size = evaluator.size_of_sized(ty, locals, "type of interval")?;
277        Ok(IntervalAndTy { interval: Interval { addr, size }, ty })
278    }
279}
280
281enum IntervalOrOwned {
282    Owned(Vec<u8>),
283    Borrowed(Interval),
284}
285
286impl From<Interval> for IntervalOrOwned {
287    fn from(it: Interval) -> IntervalOrOwned {
288        IntervalOrOwned::Borrowed(it)
289    }
290}
291
292impl IntervalOrOwned {
293    fn get<'b, 'a, 'db>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {
294        Ok(match self {
295            IntervalOrOwned::Owned(o) => o,
296            IntervalOrOwned::Borrowed(b) => b.get(memory)?,
297        })
298    }
299}
300
301#[cfg(target_pointer_width = "64")]
302const STACK_OFFSET: usize = 1 << 60;
303#[cfg(target_pointer_width = "64")]
304const HEAP_OFFSET: usize = 1 << 59;
305
306#[cfg(target_pointer_width = "32")]
307const STACK_OFFSET: usize = 1 << 30;
308#[cfg(target_pointer_width = "32")]
309const HEAP_OFFSET: usize = 1 << 29;
310
311impl Address {
312    fn from_bytes<'db>(it: &[u8]) -> Result<'db, Self> {
313        Ok(Address::from_usize(from_bytes!(usize, it)))
314    }
315
316    fn from_usize(it: usize) -> Self {
317        if it > STACK_OFFSET {
318            Stack(it - STACK_OFFSET)
319        } else if it > HEAP_OFFSET {
320            Heap(it - HEAP_OFFSET)
321        } else {
322            Invalid(it)
323        }
324    }
325
326    fn to_bytes(&self) -> [u8; size_of::<usize>()] {
327        usize::to_le_bytes(self.to_usize())
328    }
329
330    fn to_usize(&self) -> usize {
331        match self {
332            Stack(it) => *it + STACK_OFFSET,
333            Heap(it) => *it + HEAP_OFFSET,
334            Invalid(it) => *it,
335        }
336    }
337
338    fn map(&self, f: impl FnOnce(usize) -> usize) -> Address {
339        match self {
340            Stack(it) => Stack(f(*it)),
341            Heap(it) => Heap(f(*it)),
342            Invalid(it) => Invalid(f(*it)),
343        }
344    }
345
346    fn offset(&self, offset: usize) -> Address {
347        self.map(|it| it + offset)
348    }
349}
350
351#[derive(Clone, PartialEq, Eq, SalsaValue)]
352pub enum MirEvalError<'db> {
353    ConstEvalError(String, Box<ConstEvalError<'db>>),
354    LayoutError(LayoutError, StoredTy),
355    TargetDataLayoutNotAvailable(TargetLoadError),
356    /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected
357    /// then use this type of error.
358    UndefinedBehavior(String),
359    Panic(String),
360    // FIXME: This should be folded into ConstEvalError?
361    MirLowerError(FunctionId, MirLowerError<'db>),
362    MirLowerErrorForClosure(InternedClosureId<'db>, MirLowerError<'db>),
363    TypeIsUnsized(StoredTy, &'static str),
364    NotSupported(String),
365    InvalidConst,
366    InFunction(
367        Box<MirEvalError<'db>>,
368        Vec<(Either<FunctionId, InternedClosureId<'db>>, MirSpan, InferBodyId<'db>)>,
369    ),
370    ExecutionLimitExceeded,
371    StackOverflow,
372    /// FIXME: Fold this into InternalError
373    InvalidVTableId(usize),
374    /// ?
375    CoerceUnsizedError(StoredTy),
376    /// These should not occur, usually indicates a bug in mir lowering.
377    InternalError(Box<str>),
378}
379
380impl MirEvalError<'_> {
381    pub fn pretty_print(
382        &self,
383        f: &mut String,
384        db: &dyn HirDatabase,
385        span_formatter: impl Fn(FileId, TextRange) -> String,
386        display_target: DisplayTarget,
387    ) -> std::result::Result<(), std::fmt::Error> {
388        writeln!(f, "Mir eval error:")?;
389        let mut err = self;
390        while let MirEvalError::InFunction(e, stack) = err {
391            err = e;
392            for (func, span, def) in stack.iter().take(30).rev() {
393                match func {
394                    Either::Left(func) => {
395                        let function_name = FunctionSignature::of(db, *func);
396                        writeln!(
397                            f,
398                            "In function {} ({:?})",
399                            function_name.name.display(db, display_target.edition),
400                            func
401                        )?;
402                    }
403                    Either::Right(closure) => {
404                        writeln!(f, "In {closure:?}")?;
405                    }
406                }
407                let (source_map, self_param_syntax) = match *def {
408                    InferBodyId::DefWithBodyId(def) => {
409                        let body = &Body::with_source_map(db, def).1;
410                        (&**body, body.self_param_syntax())
411                    }
412                    InferBodyId::AnonConstId(def) => {
413                        let store = ExpressionStore::with_source_map(db, def.loc(db).owner).1;
414                        (store, None)
415                    }
416                };
417                let span: InFile<SyntaxNodePtr> = match *span {
418                    MirSpan::ExprId(e) => match source_map.expr_syntax(e) {
419                        Ok(s) => s.map(|it| it.into()),
420                        Err(_) => continue,
421                    },
422                    MirSpan::PatId(p) => match source_map.pat_syntax(p) {
423                        Ok(s) => s.map(|it| it.syntax_node_ptr()),
424                        Err(_) => continue,
425                    },
426                    MirSpan::BindingId(b) => {
427                        match source_map
428                            .patterns_for_binding(b)
429                            .iter()
430                            .find_map(|p| source_map.pat_syntax(*p).ok())
431                        {
432                            Some(s) => s.map(|it| it.syntax_node_ptr()),
433                            None => continue,
434                        }
435                    }
436                    MirSpan::SelfParam => match self_param_syntax {
437                        Some(s) => s.map(|it| it.syntax_node_ptr()),
438                        None => continue,
439                    },
440                    MirSpan::Unknown => continue,
441                };
442                let file_id = span.file_id.original_file(db);
443                let text_range = span.value.text_range();
444                writeln!(f, "{}", span_formatter(file_id.file_id(db), text_range))?;
445            }
446        }
447        match err {
448            MirEvalError::InFunction(..) => unreachable!(),
449            MirEvalError::LayoutError(err, ty) => {
450                write!(
451                    f,
452                    "Layout for type `{}` is not available due {err:?}",
453                    ty.as_ref()
454                        .display(db, display_target)
455                        .with_closure_style(ClosureStyle::ClosureWithId)
456                )?;
457            }
458            MirEvalError::MirLowerError(func, err) => {
459                let function_name = FunctionSignature::of(db, *func);
460                let self_ = match func.lookup(db).container {
461                    ItemContainerId::ImplId(impl_id) => Some({
462                        db.impl_self_ty(impl_id)
463                            .instantiate_identity()
464                            .skip_norm_wip()
465                            .display(db, display_target)
466                            .to_string()
467                    }),
468                    ItemContainerId::TraitId(it) => Some(
469                        TraitSignature::of(db, it)
470                            .name
471                            .display(db, display_target.edition)
472                            .to_string(),
473                    ),
474                    _ => None,
475                };
476                writeln!(
477                    f,
478                    "MIR lowering for function `{}{}{}` ({:?}) failed due:",
479                    self_.as_deref().unwrap_or_default(),
480                    if self_.is_some() { "::" } else { "" },
481                    function_name.name.display(db, display_target.edition),
482                    func
483                )?;
484                err.pretty_print(f, db, span_formatter, display_target)?;
485            }
486            MirEvalError::ConstEvalError(name, err) => {
487                MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
488                    f,
489                    db,
490                    span_formatter,
491                    display_target,
492                )?;
493            }
494            MirEvalError::UndefinedBehavior(_)
495            | MirEvalError::TargetDataLayoutNotAvailable(_)
496            | MirEvalError::Panic(_)
497            | MirEvalError::MirLowerErrorForClosure(_, _)
498            | MirEvalError::TypeIsUnsized(_, _)
499            | MirEvalError::NotSupported(_)
500            | MirEvalError::InvalidConst
501            | MirEvalError::ExecutionLimitExceeded
502            | MirEvalError::StackOverflow
503            | MirEvalError::CoerceUnsizedError(_)
504            | MirEvalError::InternalError(_)
505            | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?,
506        }
507        Ok(())
508    }
509
510    pub fn is_panic(&self) -> Option<&str> {
511        let mut err = self;
512        while let MirEvalError::InFunction(e, _) = err {
513            err = e;
514        }
515        match err {
516            MirEvalError::Panic(msg) => Some(msg),
517            _ => None,
518        }
519    }
520}
521
522impl std::fmt::Debug for MirEvalError<'_> {
523    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
524        match self {
525            Self::ConstEvalError(arg0, arg1) => {
526                f.debug_tuple("ConstEvalError").field(arg0).field(arg1).finish()
527            }
528            Self::LayoutError(arg0, arg1) => {
529                f.debug_tuple("LayoutError").field(arg0).field(arg1).finish()
530            }
531            Self::UndefinedBehavior(arg0) => {
532                f.debug_tuple("UndefinedBehavior").field(arg0).finish()
533            }
534            Self::Panic(msg) => write!(f, "Panic with message:\n{msg:?}"),
535            Self::TargetDataLayoutNotAvailable(arg0) => {
536                f.debug_tuple("TargetDataLayoutNotAvailable").field(arg0).finish()
537            }
538            Self::TypeIsUnsized(ty, it) => write!(f, "{ty:?} is unsized. {it} should be sized."),
539            Self::ExecutionLimitExceeded => write!(f, "execution limit exceeded"),
540            Self::StackOverflow => write!(f, "stack overflow"),
541            Self::MirLowerError(arg0, arg1) => {
542                f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish()
543            }
544            Self::MirLowerErrorForClosure(arg0, arg1) => {
545                f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish()
546            }
547            Self::CoerceUnsizedError(arg0) => {
548                f.debug_tuple("CoerceUnsizedError").field(arg0).finish()
549            }
550            Self::InternalError(arg0) => f.debug_tuple("InternalError").field(arg0).finish(),
551            Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),
552            Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),
553            Self::InvalidConst => f.write_str("InvalidConst"),
554            Self::InFunction(e, stack) => {
555                f.debug_struct("WithStack").field("error", e).field("stack", &stack).finish()
556            }
557        }
558    }
559}
560
561type Result<'db, T> = std::result::Result<T, MirEvalError<'db>>;
562
563#[derive(Debug, Default)]
564struct DropFlags<'db> {
565    need_drop: FxHashSet<Place<'db>>,
566}
567
568impl<'db> DropFlags<'db> {
569    fn add_place(&mut self, p: Place<'db>) {
570        if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) {
571            return;
572        }
573        self.need_drop.retain(|it| !p.is_parent(*it));
574        self.need_drop.insert(p);
575    }
576
577    fn remove_place(&mut self, p: Place<'db>) -> bool {
578        // FIXME: replace parents with parts
579        if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(it)) {
580            self.need_drop.remove(&parent);
581            return true;
582        }
583        self.need_drop.remove(&p)
584    }
585
586    fn clear(&mut self) {
587        self.need_drop.clear();
588    }
589}
590
591#[derive(Debug)]
592struct Locals<'a, 'db> {
593    ptr: ArenaMap<LocalId, Interval>,
594    body: &'db MirBody<'db>,
595    drop_flags: DropFlags<'a>,
596}
597
598pub struct MirOutput {
599    stdout: Vec<u8>,
600    stderr: Vec<u8>,
601}
602
603impl MirOutput {
604    pub fn stdout(&self) -> Cow<'_, str> {
605        String::from_utf8_lossy(&self.stdout)
606    }
607    pub fn stderr(&self) -> Cow<'_, str> {
608        String::from_utf8_lossy(&self.stderr)
609    }
610}
611
612pub fn interpret_mir<'db>(
613    db: &'db dyn HirDatabase,
614    body: &'db MirBody<'db>,
615    // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now
616    // they share their body with their parent, so in MIR lowering we have locals of the parent body, which
617    // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has
618    // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can
619    // (and probably should) do better here, for example by excluding bindings outside of the target expression.
620    assert_placeholder_ty_is_unused: bool,
621    trait_env: Option<ParamEnvAndCrate<'db>>,
622) -> Result<'db, (Result<'db, Allocation<'db>>, MirOutput)> {
623    let ty = body.locals[return_slot()].ty.as_ref();
624    let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;
625    let it: Result<'db, Allocation<'db>> = (|| {
626        if evaluator.ptr_size() != size_of::<usize>() {
627            not_supported!("targets with different pointer size from host");
628        }
629        let interval = evaluator.interpret_mir(body, None.into_iter())?;
630        let bytes = interval.get(&evaluator)?;
631        let mut memory_map = evaluator.create_memory_map(
632            bytes,
633            ty,
634            &Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },
635        )?;
636        let bytes = Box::from(bytes);
637        let memory_map = if memory_map.memory.is_empty() && evaluator.vtable_map.is_empty() {
638            MemoryMap::Empty
639        } else {
640            memory_map.vtable = mem::take(&mut evaluator.vtable_map);
641            memory_map.vtable.shrink_to_fit();
642            MemoryMap::Complex(Box::new(memory_map))
643        };
644        Ok(Allocation::new(AllocationData { ty, memory: bytes, memory_map }))
645    })();
646    Ok((it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr }))
647}
648
649#[cfg(test)]
650const EXECUTION_LIMIT: usize = 100_000;
651#[cfg(not(test))]
652const EXECUTION_LIMIT: usize = 10_000_000;
653
654impl<'a, 'db> Evaluator<'a, 'db> {
655    pub fn new(
656        db: &'db dyn HirDatabase,
657        owner: InferBodyId<'db>,
658        assert_placeholder_ty_is_unused: bool,
659        trait_env: Option<ParamEnvAndCrate<'db>>,
660    ) -> Result<'db, Evaluator<'a, 'db>> {
661        let module = owner.module(db);
662        let crate_id = module.krate(db);
663        let target_data_layout = match db.target_data_layout(crate_id) {
664            Ok(target_data_layout) => target_data_layout,
665            Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)),
666        };
667        let cached_ptr_size = target_data_layout.pointer_size().bytes_usize();
668        let interner = DbInterner::new_with(db, crate_id);
669        let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
670        let lang_items = interner.lang_items();
671        Ok(Evaluator {
672            target_data_layout,
673            stack: vec![0],
674            heap: vec![0],
675            code_stack: vec![],
676            vtable_map: VTableMap::default(),
677            thread_local_storage: TlsData::default(),
678            static_locations: Default::default(),
679            db,
680            random_state: oorandom::Rand64::new(0),
681            param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate {
682                param_env: db.trait_environment(owner.generic_def(db)),
683                krate: crate_id,
684            }),
685            crate_id,
686            stdout: vec![],
687            stderr: vec![],
688            assert_placeholder_ty_is_unused,
689            stack_depth_limit: 100,
690            execution_limit: EXECUTION_LIMIT,
691            memory_limit: 1_000_000_000, // 2GB, 1GB for stack and 1GB for heap
692            layout_cache: RefCell::new(Default::default()),
693            projected_ty_cache: RefCell::new(Default::default()),
694            not_special_fn_cache: RefCell::new(Default::default()),
695            mir_or_dyn_index_cache: RefCell::new(Default::default()),
696            unused_locals_store: RefCell::new(Default::default()),
697            cached_ptr_size,
698            cached_fn_trait_func: lang_items.Fn_call,
699            cached_fn_mut_trait_func: lang_items.FnMut_call_mut,
700            cached_fn_once_trait_func: lang_items.FnOnce_call_once,
701            infcx,
702        })
703    }
704
705    #[inline]
706    fn interner(&self) -> DbInterner<'db> {
707        self.infcx.interner
708    }
709
710    #[inline]
711    fn lang_items(&self) -> &'db LangItems {
712        self.infcx.interner.lang_items()
713    }
714
715    fn place_addr(&self, p: &StoredPlace, locals: &Locals<'a, 'db>) -> Result<'db, Address> {
716        Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0)
717    }
718
719    fn place_interval(&self, p: &StoredPlace, locals: &Locals<'a, 'db>) -> Result<'db, Interval> {
720        let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?;
721        Ok(Interval {
722            addr: place_addr_and_ty.0,
723            size: self.size_of_sized(
724                place_addr_and_ty.1,
725                locals,
726                "Type of place that we need its interval",
727            )?,
728        })
729    }
730
731    fn ptr_size(&self) -> usize {
732        self.cached_ptr_size
733    }
734
735    fn caller_location_fields(&self, owner: InferBodyId<'db>, span: MirSpan) -> (String, u32, u32) {
736        let Some((file_id, text_range)) = self.resolve_mir_span(owner, span) else {
737            return (String::new(), 0, 0);
738        };
739        let source_root = self.db.file_source_root(file_id).source_root_id(self.db);
740        let source_root = self.db.source_root(source_root).source_root(self.db);
741        let path = source_root.path_for_file(&file_id).map(|path| path.to_string());
742        let (line, col) = self.db.line_column(file_id, text_range.start()).unwrap_or((0, 0));
743        (path.unwrap_or_default(), line + 1, col + 1)
744    }
745
746    fn resolve_mir_span(
747        &self,
748        owner: InferBodyId<'db>,
749        span: MirSpan,
750    ) -> Option<(FileId, TextRange)> {
751        let (source_map, self_param_syntax) = match owner {
752            InferBodyId::DefWithBodyId(def) => {
753                let body = &Body::with_source_map(self.db, def).1;
754                (&**body, body.self_param_syntax())
755            }
756            InferBodyId::AnonConstId(def) => {
757                (ExpressionStore::with_source_map(self.db, def.loc(self.db).owner).1, None)
758            }
759        };
760        let span: InFile<SyntaxNodePtr> = match span {
761            MirSpan::ExprId(e) => source_map.expr_syntax(e).ok()?.map(|it| it.into()),
762            MirSpan::PatId(p) => source_map.pat_syntax(p).ok()?.map(|it| it.syntax_node_ptr()),
763            MirSpan::BindingId(b) => source_map
764                .patterns_for_binding(b)
765                .iter()
766                .find_map(|p| source_map.pat_syntax(*p).ok())?
767                .map(|it| it.syntax_node_ptr()),
768            MirSpan::SelfParam => self_param_syntax?.map(|it| it.syntax_node_ptr()),
769            MirSpan::Unknown => return None,
770        };
771        let file_id = span.file_id.original_file(self.db);
772        Some((file_id.file_id(self.db), span.value.text_range()))
773    }
774
775    fn projected_ty(&self, ty: PlaceTy<'db>, proj: PlaceElem) -> PlaceTy<'db> {
776        let pair = (ty, proj);
777        if let Some(r) = self.projected_ty_cache.borrow().get(&pair) {
778            return *r;
779        }
780        let (ty, proj) = pair;
781        let r = ty.projection_ty(&self.infcx, &proj, self.param_env.param_env);
782        self.projected_ty_cache.borrow_mut().insert((ty, proj), r);
783        r
784    }
785
786    fn place_addr_and_ty_and_metadata<'b>(
787        &'b self,
788        p: &StoredPlace,
789        locals: &'b Locals<'a, 'db>,
790    ) -> Result<'db, (Address, Ty<'db>, Option<IntervalOrOwned>)> {
791        let mut addr = locals.ptr[p.local].addr;
792        let mut ty = PlaceTy::from_ty(locals.body.locals[p.local].ty.as_ref());
793        let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized
794        for proj in p.projection.as_slice() {
795            let prev_ty = ty;
796            ty = self.projected_ty(ty, *proj);
797            match proj {
798                ProjectionElem::Deref => {
799                    metadata = if self.size_align_of(ty.ty, locals)?.is_none() {
800                        Some(
801                            Interval { addr: addr.offset(self.ptr_size()), size: self.ptr_size() }
802                                .into(),
803                        )
804                    } else {
805                        None
806                    };
807                    let it = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?);
808                    addr = Address::from_usize(it);
809                }
810                ProjectionElem::Index(op) => {
811                    let offset = from_bytes!(
812                        usize,
813                        self.read_memory(locals.ptr[*op].addr, self.ptr_size())?
814                    );
815                    metadata = None; // Result of index is always sized
816                    let ty_size = self.size_of_sized(ty.ty, locals, "array inner type")?;
817                    addr = addr.offset(ty_size * offset);
818                }
819                &ProjectionElem::ConstantIndex { from_end, offset } => {
820                    let offset = if from_end {
821                        let len = match prev_ty.ty.kind() {
822                            TyKind::Array(_, c) => match try_const_usize(self.db, c) {
823                                Some(it) => it as u64,
824                                None => {
825                                    not_supported!("indexing array with unknown const from end")
826                                }
827                            },
828                            TyKind::Slice(_) => match metadata {
829                                Some(it) => from_bytes!(u64, it.get(self)?),
830                                None => not_supported!("slice place without metadata"),
831                            },
832                            _ => not_supported!("bad type for const index"),
833                        };
834                        (len - offset - 1) as usize
835                    } else {
836                        offset as usize
837                    };
838                    metadata = None; // Result of index is always sized
839                    let ty_size = self.size_of_sized(ty.ty, locals, "array inner type")?;
840                    addr = addr.offset(ty_size * offset);
841                }
842                &ProjectionElem::Subslice { from, to } => {
843                    let inner_ty = match ty.ty.kind() {
844                        TyKind::Array(inner, _) | TyKind::Slice(inner) => inner,
845                        _ => Ty::new_error(self.interner(), ErrorGuaranteed),
846                    };
847                    metadata = match metadata {
848                        Some(it) => {
849                            let prev_len = from_bytes!(u64, it.get(self)?);
850                            Some(IntervalOrOwned::Owned(
851                                (prev_len - from - to).to_le_bytes().to_vec(),
852                            ))
853                        }
854                        None => None,
855                    };
856                    let ty_size = self.size_of_sized(inner_ty, locals, "array inner type")?;
857                    addr = addr.offset(ty_size * (from as usize));
858                }
859                ProjectionElem::Field(f) => {
860                    let layout = self.layout(prev_ty.ty)?;
861                    let variant_layout = match &layout.variants {
862                        Variants::Single { .. } | Variants::Empty => &layout,
863                        Variants::Multiple { variants, .. } => {
864                            &variants[match prev_ty.variant_id {
865                                Some(hir_def::VariantId::EnumVariantId(it)) => {
866                                    RustcEnumVariantIdx(it.index(self.db))
867                                }
868                                _ => {
869                                    return Err(MirEvalError::InternalError(
870                                        "mismatched layout".into(),
871                                    ));
872                                }
873                            }]
874                        }
875                    };
876                    let offset = variant_layout.fields.offset(f.0 as usize).bytes_usize();
877                    addr = addr.offset(offset);
878                    // Unsized field metadata is equal to the metadata of the struct
879                    if self.size_align_of(ty.ty, locals)?.is_some() {
880                        metadata = None;
881                    }
882                }
883                ProjectionElem::Downcast(_) => {
884                    // no runtime effect
885                }
886            }
887        }
888        Ok((addr, ty.ty, metadata))
889    }
890
891    fn layout(&self, ty: Ty<'db>) -> Result<'db, Arc<Layout>> {
892        if let Some(x) = self.layout_cache.borrow().get(&ty) {
893            return Ok(x.clone());
894        }
895        let r = self
896            .db
897            .layout_of_ty(ty.store(), self.param_env.store())
898            .map_err(|e| MirEvalError::LayoutError(e, ty.store()))?;
899        self.layout_cache.borrow_mut().insert(ty, r.clone());
900        Ok(r)
901    }
902
903    fn layout_adt(&self, adt: AdtId, subst: GenericArgs<'db>) -> Result<'db, Arc<Layout>> {
904        self.layout(Ty::new_adt(self.interner(), adt, subst))
905    }
906
907    fn place_ty<'b>(
908        &'b self,
909        p: &StoredPlace,
910        locals: &'b Locals<'a, 'db>,
911    ) -> Result<'db, Ty<'db>> {
912        Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1)
913    }
914
915    fn operand_ty(&self, o: &Operand, locals: &Locals<'a, 'db>) -> Result<'db, Ty<'db>> {
916        Ok(match &o.kind {
917            OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?,
918            OperandKind::Constant { konst: _, ty } => ty.as_ref(),
919            OperandKind::Allocation { allocation } => allocation.as_ref().ty,
920            &OperandKind::Static(s) => {
921                let ty = InferenceResult::of(self.db, DefWithBodyId::from(s))
922                    .expr_ty(Body::of(self.db, s.into()).root_expr());
923                Ty::new_ref(
924                    self.interner(),
925                    Region::new_static(self.interner()),
926                    ty,
927                    Mutability::Not,
928                )
929            }
930        })
931    }
932
933    fn operand_ty_and_eval(
934        &mut self,
935        o: &Operand,
936        locals: &mut Locals<'a, 'db>,
937    ) -> Result<'db, IntervalAndTy<'db>> {
938        Ok(IntervalAndTy {
939            interval: self.eval_operand(o, locals)?,
940            ty: self.operand_ty(o, locals)?,
941        })
942    }
943
944    fn interpret_mir(
945        &mut self,
946        body: &'db MirBody<'db>,
947        args: impl Iterator<Item = IntervalOrOwned>,
948    ) -> Result<'db, Interval> {
949        if let Some(it) = self.stack_depth_limit.checked_sub(1) {
950            self.stack_depth_limit = it;
951        } else {
952            return Err(MirEvalError::StackOverflow);
953        }
954        let mut current_block_idx = body.start_block;
955        let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body, None)?;
956        self.fill_locals_for_body(body, &mut locals, args)?;
957        let prev_code_stack = mem::take(&mut self.code_stack);
958        let span = (MirSpan::Unknown, body.owner);
959        self.code_stack.push(StackFrame { locals, destination: None, prev_stack_ptr, span });
960        'stack: loop {
961            let Some(mut my_stack_frame) = self.code_stack.pop() else {
962                not_supported!("missing stack frame");
963            };
964            let e = (|| {
965                let locals = &mut my_stack_frame.locals;
966                let body = locals.body.clone();
967                loop {
968                    let current_block = &body.basic_blocks[current_block_idx];
969                    if let Some(it) = self.execution_limit.checked_sub(1) {
970                        self.execution_limit = it;
971                    } else {
972                        return Err(MirEvalError::ExecutionLimitExceeded);
973                    }
974                    for statement in &current_block.statements {
975                        match &statement.kind {
976                            StatementKind::Assign(l, r) => {
977                                let addr = self.place_addr(l, locals)?;
978                                let result = self.eval_rvalue(r, locals)?;
979                                self.copy_from_interval_or_owned(addr, result)?;
980                                locals.drop_flags.add_place(l.as_ref());
981                            }
982                            StatementKind::Deinit(_) => not_supported!("de-init statement"),
983                            StatementKind::StorageLive(_)
984                            | StatementKind::FakeRead(_)
985                            | StatementKind::StorageDead(_)
986                            | StatementKind::Nop => (),
987                        }
988                    }
989                    let Some(terminator) = current_block.terminator.as_ref() else {
990                        not_supported!("block without terminator");
991                    };
992                    match &terminator.kind {
993                        TerminatorKind::Goto { target } => {
994                            current_block_idx = *target;
995                        }
996                        TerminatorKind::Call {
997                            func,
998                            args,
999                            destination,
1000                            target,
1001                            cleanup: _,
1002                            from_hir_call: _,
1003                        } => {
1004                            let destination_interval = self.place_interval(destination, locals)?;
1005                            let fn_ty = self.operand_ty(func, locals)?;
1006                            let args = args
1007                                .iter()
1008                                .map(|it| self.operand_ty_and_eval(it, locals))
1009                                .collect::<Result<'db, Vec<_>>>()?;
1010                            let stack_frame = match fn_ty.kind() {
1011                                TyKind::FnPtr(..) => {
1012                                    let bytes = self.eval_operand(func, locals)?;
1013                                    self.exec_fn_pointer(
1014                                        bytes,
1015                                        destination_interval,
1016                                        &args,
1017                                        locals,
1018                                        *target,
1019                                        terminator.span,
1020                                    )?
1021                                }
1022                                TyKind::FnDef(def, generic_args) => self.exec_fn_def(
1023                                    def.0,
1024                                    generic_args,
1025                                    destination_interval,
1026                                    &args,
1027                                    locals,
1028                                    *target,
1029                                    terminator.span,
1030                                )?,
1031                                it => not_supported!("unknown function type {it:?}"),
1032                            };
1033                            locals.drop_flags.add_place(destination.as_ref());
1034                            if let Some(stack_frame) = stack_frame {
1035                                self.code_stack.push(my_stack_frame);
1036                                current_block_idx = stack_frame.locals.body.start_block;
1037                                self.code_stack.push(stack_frame);
1038                                return Ok(None);
1039                            } else {
1040                                current_block_idx =
1041                                    target.ok_or(MirEvalError::UndefinedBehavior(
1042                                        "Diverging function returned".to_owned(),
1043                                    ))?;
1044                            }
1045                        }
1046                        TerminatorKind::SwitchInt { discr, targets } => {
1047                            let val = u128::from_le_bytes(pad16(
1048                                self.eval_operand(discr, locals)?.get(self)?,
1049                                IsSigned::No,
1050                            ));
1051                            current_block_idx = targets.target_for_value(val);
1052                        }
1053                        TerminatorKind::Return => {
1054                            break;
1055                        }
1056                        TerminatorKind::Unreachable => {
1057                            return Err(MirEvalError::UndefinedBehavior(
1058                                "unreachable executed".to_owned(),
1059                            ));
1060                        }
1061                        TerminatorKind::Drop { place, target, unwind: _ } => {
1062                            self.drop_place(place, locals, terminator.span)?;
1063                            current_block_idx = *target;
1064                        }
1065                        _ => not_supported!("unknown terminator"),
1066                    }
1067                }
1068                Ok(Some(my_stack_frame))
1069            })();
1070            let my_stack_frame = match e {
1071                Ok(None) => continue 'stack,
1072                Ok(Some(x)) => x,
1073                Err(e) => {
1074                    let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack);
1075                    let mut error_stack = vec![];
1076                    for frame in my_code_stack.into_iter().rev() {
1077                        if let Some(f) = frame.locals.body.owner.as_function() {
1078                            error_stack.push((Either::Left(f), frame.span.0, frame.span.1));
1079                        }
1080                    }
1081                    return Err(MirEvalError::InFunction(Box::new(e), error_stack));
1082                }
1083            };
1084            let return_interval = my_stack_frame.locals.ptr[return_slot()];
1085            self.unused_locals_store
1086                .borrow_mut()
1087                .entry(my_stack_frame.locals.body.owner)
1088                .or_default()
1089                .push(my_stack_frame.locals);
1090            match my_stack_frame.destination {
1091                None => {
1092                    self.code_stack = prev_code_stack;
1093                    self.stack_depth_limit += 1;
1094                    return Ok(return_interval);
1095                }
1096                Some(bb) => {
1097                    // We don't support const promotion, so we can't truncate the stack yet.
1098                    let _ = my_stack_frame.prev_stack_ptr;
1099                    // self.stack.truncate(my_stack_frame.prev_stack_ptr);
1100                    current_block_idx = bb;
1101                }
1102            }
1103        }
1104    }
1105
1106    fn fill_locals_for_body(
1107        &mut self,
1108        body: &'db MirBody<'db>,
1109        locals: &mut Locals<'a, 'db>,
1110        args: impl Iterator<Item = IntervalOrOwned>,
1111    ) -> Result<'db, ()> {
1112        let mut remain_args = body.param_locals.len();
1113        for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {
1114            locals.drop_flags.add_place(l.into());
1115            match value {
1116                IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,
1117                IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,
1118            }
1119            if remain_args == 0 {
1120                return Err(MirEvalError::InternalError("too many arguments".into()));
1121            }
1122            remain_args -= 1;
1123        }
1124        if remain_args > 0 {
1125            return Err(MirEvalError::InternalError("too few arguments".into()));
1126        }
1127        Ok(())
1128    }
1129
1130    fn create_locals_for_body(
1131        &mut self,
1132        body: &'db MirBody<'db>,
1133        destination: Option<Interval>,
1134    ) -> Result<'db, (Locals<'a, 'db>, usize)> {
1135        let mut locals =
1136            match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() {
1137                None => Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },
1138                Some(mut l) => {
1139                    l.drop_flags.clear();
1140                    l.body = body;
1141                    l
1142                }
1143            };
1144        let stack_size = {
1145            let mut stack_ptr = self.stack.len();
1146            for (id, it) in body.locals.iter() {
1147                if id == return_slot()
1148                    && let Some(destination) = destination
1149                {
1150                    locals.ptr.insert(id, destination);
1151                    continue;
1152                }
1153                let (size, align) = self.size_align_of_sized(
1154                    it.ty.as_ref(),
1155                    &locals,
1156                    "no unsized local in extending stack",
1157                )?;
1158                while !stack_ptr.is_multiple_of(align) {
1159                    stack_ptr += 1;
1160                }
1161                let my_ptr = stack_ptr;
1162                stack_ptr += size;
1163                locals.ptr.insert(id, Interval { addr: Stack(my_ptr), size });
1164            }
1165            stack_ptr - self.stack.len()
1166        };
1167        let prev_stack_pointer = self.stack.len();
1168        if stack_size > self.memory_limit {
1169            return Err(MirEvalError::Panic(format!(
1170                "Stack overflow. Tried to grow stack to {stack_size} bytes"
1171            )));
1172        }
1173        self.stack.extend(std::iter::repeat_n(0, stack_size));
1174        Ok((locals, prev_stack_pointer))
1175    }
1176
1177    fn eval_rvalue(
1178        &mut self,
1179        r: &Rvalue,
1180        locals: &mut Locals<'a, 'db>,
1181    ) -> Result<'db, IntervalOrOwned> {
1182        use IntervalOrOwned::*;
1183        Ok(match r {
1184            Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?),
1185            Rvalue::Ref(_, p) => {
1186                let (addr, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?;
1187                let mut r = addr.to_bytes().to_vec();
1188                if let Some(metadata) = metadata {
1189                    r.extend(metadata.get(self)?);
1190                }
1191                Owned(r)
1192            }
1193            Rvalue::Len(p) => {
1194                let (_, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?;
1195                match metadata {
1196                    Some(m) => m,
1197                    None => {
1198                        return Err(MirEvalError::InternalError(
1199                            "type without metadata is used for Rvalue::Len".into(),
1200                        ));
1201                    }
1202                }
1203            }
1204            Rvalue::UnaryOp(op, val) => {
1205                let mut c = self.eval_operand(val, locals)?.get(self)?;
1206                let mut ty = self.operand_ty(val, locals)?;
1207                while let TyKind::Ref(_, z, _) = ty.kind() {
1208                    ty = z;
1209                    let size = self.size_of_sized(ty, locals, "operand of unary op")?;
1210                    c = self.read_memory(Address::from_bytes(c)?, size)?;
1211                }
1212                if let TyKind::Float(f) = ty.kind() {
1213                    match f {
1214                        rustc_type_ir::FloatTy::F16 => {
1215                            let c = -from_bytes!(f16, u16, c);
1216                            Owned(u16::try_from(c.to_bits()).unwrap().to_le_bytes().into())
1217                        }
1218                        rustc_type_ir::FloatTy::F32 => {
1219                            let c = -from_bytes!(f32, c);
1220                            Owned(c.to_le_bytes().into())
1221                        }
1222                        rustc_type_ir::FloatTy::F64 => {
1223                            let c = -from_bytes!(f64, c);
1224                            Owned(c.to_le_bytes().into())
1225                        }
1226                        rustc_type_ir::FloatTy::F128 => {
1227                            let c = -from_bytes!(f128, u128, c);
1228                            Owned(c.to_bits().to_le_bytes().into())
1229                        }
1230                    }
1231                } else {
1232                    let mut c = c.to_vec();
1233                    if matches!(ty.kind(), TyKind::Bool) {
1234                        c[0] = 1 - c[0];
1235                    } else {
1236                        match op {
1237                            UnOp::Not => c.iter_mut().for_each(|it| *it = !*it),
1238                            UnOp::Neg => {
1239                                c.iter_mut().for_each(|it| *it = !*it);
1240                                for k in c.iter_mut() {
1241                                    let o;
1242                                    (*k, o) = k.overflowing_add(1);
1243                                    if !o {
1244                                        break;
1245                                    }
1246                                }
1247                            }
1248                        }
1249                    }
1250                    Owned(c)
1251                }
1252            }
1253            Rvalue::CheckedBinaryOp(op, lhs, rhs) => 'binary_op: {
1254                let lc = self.eval_operand(lhs, locals)?;
1255                let rc = self.eval_operand(rhs, locals)?;
1256                let mut lc = lc.get(self)?;
1257                let mut rc = rc.get(self)?;
1258                let mut ty = self.operand_ty(lhs, locals)?;
1259                while let TyKind::Ref(_, z, _) = ty.kind() {
1260                    ty = z;
1261                    let size = if ty.is_str() {
1262                        if *op != BinOp::Eq {
1263                            return Err(MirEvalError::NotSupported(
1264                                "Only eq is builtin for `str`".to_owned(),
1265                            ));
1266                        }
1267                        let ls = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]);
1268                        let rs = from_bytes!(usize, &rc[self.ptr_size()..self.ptr_size() * 2]);
1269                        if ls != rs {
1270                            break 'binary_op Owned(vec![0]);
1271                        }
1272                        lc = &lc[..self.ptr_size()];
1273                        rc = &rc[..self.ptr_size()];
1274                        lc = self.read_memory(Address::from_bytes(lc)?, ls)?;
1275                        rc = self.read_memory(Address::from_bytes(rc)?, ls)?;
1276                        break 'binary_op Owned(vec![u8::from(lc == rc)]);
1277                    } else {
1278                        self.size_of_sized(ty, locals, "operand of binary op")?
1279                    };
1280                    lc = self.read_memory(Address::from_bytes(lc)?, size)?;
1281                    rc = self.read_memory(Address::from_bytes(rc)?, size)?;
1282                }
1283                if let TyKind::Float(f) = ty.kind() {
1284                    match f {
1285                        rustc_type_ir::FloatTy::F16 => {
1286                            let l = from_bytes!(f16, u16, lc);
1287                            let r = from_bytes!(f16, u16, rc);
1288                            match op {
1289                                BinOp::Ge
1290                                | BinOp::Gt
1291                                | BinOp::Le
1292                                | BinOp::Lt
1293                                | BinOp::Eq
1294                                | BinOp::Ne => {
1295                                    let r = op.run_compare(l, r) as u8;
1296                                    Owned(vec![r])
1297                                }
1298                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
1299                                    let r = match op {
1300                                        BinOp::Add => l + r,
1301                                        BinOp::Sub => l - r,
1302                                        BinOp::Mul => l * r,
1303                                        BinOp::Div => l / r,
1304                                        _ => unreachable!(),
1305                                    };
1306                                    Owned(
1307                                        u16::try_from(r.value.to_bits())
1308                                            .unwrap()
1309                                            .to_le_bytes()
1310                                            .into(),
1311                                    )
1312                                }
1313                                it => not_supported!(
1314                                    "invalid binop {it:?} on floating point operators"
1315                                ),
1316                            }
1317                        }
1318                        rustc_type_ir::FloatTy::F32 => {
1319                            let l = from_bytes!(f32, lc);
1320                            let r = from_bytes!(f32, rc);
1321                            match op {
1322                                BinOp::Ge
1323                                | BinOp::Gt
1324                                | BinOp::Le
1325                                | BinOp::Lt
1326                                | BinOp::Eq
1327                                | BinOp::Ne => {
1328                                    let r = op.run_compare(l, r) as u8;
1329                                    Owned(vec![r])
1330                                }
1331                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
1332                                    let r = match op {
1333                                        BinOp::Add => l + r,
1334                                        BinOp::Sub => l - r,
1335                                        BinOp::Mul => l * r,
1336                                        BinOp::Div => l / r,
1337                                        _ => unreachable!(),
1338                                    };
1339                                    Owned(r.to_le_bytes().into())
1340                                }
1341                                it => not_supported!(
1342                                    "invalid binop {it:?} on floating point operators"
1343                                ),
1344                            }
1345                        }
1346                        rustc_type_ir::FloatTy::F64 => {
1347                            let l = from_bytes!(f64, lc);
1348                            let r = from_bytes!(f64, rc);
1349                            match op {
1350                                BinOp::Ge
1351                                | BinOp::Gt
1352                                | BinOp::Le
1353                                | BinOp::Lt
1354                                | BinOp::Eq
1355                                | BinOp::Ne => {
1356                                    let r = op.run_compare(l, r) as u8;
1357                                    Owned(vec![r])
1358                                }
1359                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
1360                                    let r = match op {
1361                                        BinOp::Add => l + r,
1362                                        BinOp::Sub => l - r,
1363                                        BinOp::Mul => l * r,
1364                                        BinOp::Div => l / r,
1365                                        _ => unreachable!(),
1366                                    };
1367                                    Owned(r.to_le_bytes().into())
1368                                }
1369                                it => not_supported!(
1370                                    "invalid binop {it:?} on floating point operators"
1371                                ),
1372                            }
1373                        }
1374                        rustc_type_ir::FloatTy::F128 => {
1375                            let l = from_bytes!(f128, u128, lc);
1376                            let r = from_bytes!(f128, u128, rc);
1377                            match op {
1378                                BinOp::Ge
1379                                | BinOp::Gt
1380                                | BinOp::Le
1381                                | BinOp::Lt
1382                                | BinOp::Eq
1383                                | BinOp::Ne => {
1384                                    let r = op.run_compare(l, r) as u8;
1385                                    Owned(vec![r])
1386                                }
1387                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
1388                                    let r = match op {
1389                                        BinOp::Add => l + r,
1390                                        BinOp::Sub => l - r,
1391                                        BinOp::Mul => l * r,
1392                                        BinOp::Div => l / r,
1393                                        _ => unreachable!(),
1394                                    };
1395                                    Owned(r.value.to_bits().to_le_bytes().into())
1396                                }
1397                                it => not_supported!(
1398                                    "invalid binop {it:?} on floating point operators"
1399                                ),
1400                            }
1401                        }
1402                    }
1403                } else {
1404                    let is_signed = matches!(ty.kind(), TyKind::Int(_));
1405                    let l128 = IntValue::from_bytes(lc, is_signed);
1406                    let r128 = IntValue::from_bytes(rc, is_signed);
1407                    match op {
1408                        BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => {
1409                            let r = op.run_compare(l128, r128) as u8;
1410                            Owned(vec![r])
1411                        }
1412                        BinOp::BitAnd
1413                        | BinOp::BitOr
1414                        | BinOp::BitXor
1415                        | BinOp::Add
1416                        | BinOp::Mul
1417                        | BinOp::Div
1418                        | BinOp::Rem
1419                        | BinOp::Sub => {
1420                            let r = match op {
1421                                BinOp::Add => l128.checked_add(r128).ok_or_else(|| {
1422                                    MirEvalError::Panic(format!("Overflow in {op:?}"))
1423                                })?,
1424                                BinOp::Mul => l128.checked_mul(r128).ok_or_else(|| {
1425                                    MirEvalError::Panic(format!("Overflow in {op:?}"))
1426                                })?,
1427                                BinOp::Div => l128.checked_div(r128).ok_or_else(|| {
1428                                    MirEvalError::Panic(format!("Overflow in {op:?}"))
1429                                })?,
1430                                BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| {
1431                                    MirEvalError::Panic(format!("Overflow in {op:?}"))
1432                                })?,
1433                                BinOp::Sub => l128.checked_sub(r128).ok_or_else(|| {
1434                                    MirEvalError::Panic(format!("Overflow in {op:?}"))
1435                                })?,
1436                                BinOp::BitAnd => l128 & r128,
1437                                BinOp::BitOr => l128 | r128,
1438                                BinOp::BitXor => l128 ^ r128,
1439                                _ => unreachable!(),
1440                            };
1441                            Owned(r.to_bytes())
1442                        }
1443                        BinOp::Shl | BinOp::Shr => {
1444                            let r = 'b: {
1445                                if let Some(shift_amount) = r128.as_u32() {
1446                                    let r = match op {
1447                                        BinOp::Shl => l128.checked_shl(shift_amount),
1448                                        BinOp::Shr => l128.checked_shr(shift_amount),
1449                                        _ => unreachable!(),
1450                                    };
1451                                    if shift_amount as usize >= lc.len() * 8 {
1452                                        return Err(MirEvalError::Panic(format!(
1453                                            "Overflow in {op:?}"
1454                                        )));
1455                                    }
1456                                    if let Some(r) = r {
1457                                        break 'b r;
1458                                    }
1459                                };
1460                                return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
1461                            };
1462                            Owned(r.to_bytes())
1463                        }
1464                        BinOp::Offset => not_supported!("offset binop"),
1465                    }
1466                }
1467            }
1468            Rvalue::Discriminant(p) => {
1469                let ty = self.place_ty(p, locals)?;
1470                let bytes = self.eval_place(p, locals)?.get(self)?;
1471                let result = self.compute_discriminant(ty, bytes)?;
1472                Owned(result.to_le_bytes().to_vec())
1473            }
1474            Rvalue::Repeat(it, len) => {
1475                let len = match try_const_usize(self.db, len.as_ref()) {
1476                    Some(it) => it as usize,
1477                    None => not_supported!("non evaluatable array len in repeat Rvalue"),
1478                };
1479                let val = self.eval_operand(it, locals)?.get(self)?;
1480                let size = len * val.len();
1481                Owned(val.iter().copied().cycle().take(size).collect())
1482            }
1483            Rvalue::CopyForDeref(_) => not_supported!("copy for deref"),
1484            Rvalue::Aggregate(kind, values) => {
1485                let values = values
1486                    .iter()
1487                    .map(|it| self.eval_operand(it, locals))
1488                    .collect::<Result<'db, Vec<_>>>()?;
1489                match kind {
1490                    AggregateKind::Array(_) => {
1491                        let mut r = vec![];
1492                        for it in values {
1493                            let value = it.get(self)?;
1494                            r.extend(value);
1495                        }
1496                        Owned(r)
1497                    }
1498                    AggregateKind::Tuple(ty) => {
1499                        let layout = self.layout(ty.as_ref())?;
1500                        Owned(self.construct_with_layout(
1501                            layout.size.bytes_usize(),
1502                            &layout,
1503                            None,
1504                            values.iter().map(|&it| it.into()),
1505                        )?)
1506                    }
1507                    AggregateKind::Union(it, f) => {
1508                        let layout = self.layout_adt((*it).into(), GenericArgs::empty())?;
1509                        let offset = layout
1510                            .fields
1511                            .offset(u32::from(f.local_id.into_raw()) as usize)
1512                            .bytes_usize();
1513                        let op = values[0].get(self)?;
1514                        let mut result = vec![0; layout.size.bytes_usize()];
1515                        result[offset..offset + op.len()].copy_from_slice(op);
1516                        Owned(result)
1517                    }
1518                    AggregateKind::Adt(it, subst) => {
1519                        let (size, variant_layout, tag) =
1520                            self.layout_of_variant(*it, subst.as_ref(), locals)?;
1521                        Owned(self.construct_with_layout(
1522                            size,
1523                            &variant_layout,
1524                            tag,
1525                            values.iter().map(|&it| it.into()),
1526                        )?)
1527                    }
1528                    AggregateKind::Closure(ty) => {
1529                        let layout = self.layout(ty.as_ref())?;
1530                        Owned(self.construct_with_layout(
1531                            layout.size.bytes_usize(),
1532                            &layout,
1533                            None,
1534                            values.iter().map(|&it| it.into()),
1535                        )?)
1536                    }
1537                }
1538            }
1539            Rvalue::Cast(kind, operand, target_ty) => match kind {
1540                CastKind::PointerCoercion(cast) => match cast {
1541                    PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => {
1542                        let current_ty = self.operand_ty(operand, locals)?;
1543                        if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) = current_ty.kind() {
1544                            let id = self.vtable_map.id(current_ty);
1545                            let ptr_size = self.ptr_size();
1546                            Owned(id.to_le_bytes()[0..ptr_size].to_vec())
1547                        } else {
1548                            not_supported!(
1549                                "creating a fn pointer from a non FnDef or Closure type"
1550                            );
1551                        }
1552                    }
1553                    PointerCast::Unsize => {
1554                        let current_ty = self.operand_ty(operand, locals)?;
1555                        let addr = self.eval_operand(operand, locals)?;
1556                        self.coerce_unsized(addr, current_ty, target_ty.as_ref())?
1557                    }
1558                    PointerCast::MutToConstPointer | PointerCast::UnsafeFnPointer => {
1559                        // This is no-op
1560                        Borrowed(self.eval_operand(operand, locals)?)
1561                    }
1562                    PointerCast::ArrayToPointer => {
1563                        // We should remove the metadata part if the current type is slice
1564                        Borrowed(self.eval_operand(operand, locals)?.slice(0..self.ptr_size()))
1565                    }
1566                },
1567                CastKind::DynStar => not_supported!("dyn star cast"),
1568                CastKind::IntToInt
1569                | CastKind::PtrToPtr
1570                | CastKind::PointerExposeAddress
1571                | CastKind::PointerFromExposedAddress => {
1572                    let current_ty = self.operand_ty(operand, locals)?;
1573                    let is_signed = matches!(current_ty.kind(), TyKind::Int(_)).into();
1574                    let current = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);
1575                    let dest_size = self.size_of_sized(
1576                        target_ty.as_ref(),
1577                        locals,
1578                        "destination of int to int cast",
1579                    )?;
1580                    Owned(current[0..dest_size].to_vec())
1581                }
1582                CastKind::FloatToInt => {
1583                    let ty = self.operand_ty(operand, locals)?;
1584                    let TyKind::Float(ty) = ty.kind() else {
1585                        not_supported!("invalid float to int cast");
1586                    };
1587                    let value = self.eval_operand(operand, locals)?.get(self)?;
1588                    let value = match ty {
1589                        rustc_type_ir::FloatTy::F32 => {
1590                            let value = value.try_into().unwrap();
1591                            f32::from_le_bytes(value) as f64
1592                        }
1593                        rustc_type_ir::FloatTy::F64 => {
1594                            let value = value.try_into().unwrap();
1595                            f64::from_le_bytes(value)
1596                        }
1597                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {
1598                            not_supported!("unstable floating point type f16 and f128");
1599                        }
1600                    };
1601                    let is_signed = matches!(target_ty.as_ref().kind(), TyKind::Int(_));
1602                    let dest_size = self.size_of_sized(
1603                        target_ty.as_ref(),
1604                        locals,
1605                        "destination of float to int cast",
1606                    )?;
1607                    let dest_bits = dest_size * 8;
1608                    let (max, min) = if dest_bits == 128 {
1609                        (i128::MAX, i128::MIN)
1610                    } else if is_signed {
1611                        let max = 1i128 << (dest_bits - 1);
1612                        (max - 1, -max)
1613                    } else {
1614                        ((1i128 << dest_bits) - 1, 0)
1615                    };
1616                    let value = (value as i128).min(max).max(min);
1617                    let result = value.to_le_bytes();
1618                    Owned(result[0..dest_size].to_vec())
1619                }
1620                CastKind::FloatToFloat => {
1621                    let ty = self.operand_ty(operand, locals)?;
1622                    let TyKind::Float(ty) = ty.kind() else {
1623                        not_supported!("invalid float to int cast");
1624                    };
1625                    let value = self.eval_operand(operand, locals)?.get(self)?;
1626                    let value = match ty {
1627                        rustc_type_ir::FloatTy::F32 => {
1628                            let value = value.try_into().unwrap();
1629                            f32::from_le_bytes(value) as f64
1630                        }
1631                        rustc_type_ir::FloatTy::F64 => {
1632                            let value = value.try_into().unwrap();
1633                            f64::from_le_bytes(value)
1634                        }
1635                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {
1636                            not_supported!("unstable floating point type f16 and f128");
1637                        }
1638                    };
1639                    let TyKind::Float(target_ty) = target_ty.as_ref().kind() else {
1640                        not_supported!("invalid float to float cast");
1641                    };
1642                    match target_ty {
1643                        rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),
1644                        rustc_type_ir::FloatTy::F64 => Owned(value.to_le_bytes().to_vec()),
1645                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {
1646                            not_supported!("unstable floating point type f16 and f128");
1647                        }
1648                    }
1649                }
1650                CastKind::IntToFloat => {
1651                    let current_ty = self.operand_ty(operand, locals)?;
1652                    let is_signed = matches!(current_ty.kind(), TyKind::Int(_)).into();
1653                    let value = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);
1654                    let value = i128::from_le_bytes(value);
1655                    let TyKind::Float(target_ty) = target_ty.as_ref().kind() else {
1656                        not_supported!("invalid int to float cast");
1657                    };
1658                    match target_ty {
1659                        rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),
1660                        rustc_type_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),
1661                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {
1662                            not_supported!("unstable floating point type f16 and f128");
1663                        }
1664                    }
1665                }
1666                CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
1667            },
1668            Rvalue::ThreadLocalRef(n)
1669            | Rvalue::AddressOf(n)
1670            | Rvalue::BinaryOp(n)
1671            | Rvalue::NullaryOp(n) => match *n {},
1672        })
1673    }
1674
1675    fn compute_discriminant(&self, ty: Ty<'db>, bytes: &[u8]) -> Result<'db, i128> {
1676        let layout = self.layout(ty)?;
1677        let TyKind::Adt(adt_def, _) = ty.kind() else {
1678            return Ok(0);
1679        };
1680        let AdtId::EnumId(e) = adt_def.def_id() else {
1681            return Ok(0);
1682        };
1683        match &layout.variants {
1684            Variants::Empty => Err(MirEvalError::UndefinedBehavior(
1685                "reading the discriminant of an uninhabited enum".to_owned(),
1686            )),
1687            Variants::Single { index } => {
1688                let r =
1689                    self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?;
1690                Ok(r)
1691            }
1692            Variants::Multiple { tag, tag_encoding, variants, .. } => {
1693                let size = tag.size(self.target_data_layout).bytes_usize();
1694                let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
1695                let is_signed = tag.is_signed().into();
1696                match tag_encoding {
1697                    TagEncoding::Direct => {
1698                        let tag = &bytes[offset..offset + size];
1699                        Ok(i128::from_le_bytes(pad16(tag, is_signed)))
1700                    }
1701                    TagEncoding::Niche { untagged_variant, niche_start, .. } => {
1702                        let tag = &bytes[offset..offset + size];
1703                        let candidate_tag = i128::from_le_bytes(pad16(tag, is_signed))
1704                            .wrapping_sub(*niche_start as i128)
1705                            as usize;
1706                        let idx = variants
1707                            .iter_enumerated()
1708                            .map(|(it, _)| it)
1709                            .filter(|it| it != untagged_variant)
1710                            .nth(candidate_tag)
1711                            .unwrap_or(*untagged_variant)
1712                            .0;
1713                        let result =
1714                            self.const_eval_discriminant(e.enum_variants(self.db).variants[idx].0)?;
1715                        Ok(result)
1716                    }
1717                }
1718            }
1719        }
1720    }
1721
1722    fn coerce_unsized_look_through_fields<T>(
1723        &self,
1724        ty: Ty<'db>,
1725        goal: impl Fn(TyKind<'db>) -> Option<T>,
1726    ) -> Result<'db, T> {
1727        let kind = ty.kind();
1728        if let Some(it) = goal(kind) {
1729            return Ok(it);
1730        }
1731        match kind {
1732            TyKind::Adt(adt_ef, subst) if let AdtId::StructId(struct_id) = adt_ef.def_id() => {
1733                let field_types = self.db.field_types(struct_id.into());
1734                if let Some(ty) = field_types
1735                    .iter()
1736                    .last()
1737                    .map(|it| it.1.ty().instantiate(self.interner(), subst))
1738                {
1739                    return self.coerce_unsized_look_through_fields(ty.skip_norm_wip(), goal);
1740                }
1741            }
1742            TyKind::Pat(ty, _) => return self.coerce_unsized_look_through_fields(ty, goal),
1743            _ => (),
1744        }
1745        Err(MirEvalError::CoerceUnsizedError(ty.store()))
1746    }
1747
1748    fn coerce_unsized(
1749        &mut self,
1750        addr: Interval,
1751        current_ty: Ty<'db>,
1752        target_ty: Ty<'db>,
1753    ) -> Result<'db, IntervalOrOwned> {
1754        fn for_ptr<'db>(it: TyKind<'db>) -> Option<Ty<'db>> {
1755            match it {
1756                TyKind::RawPtr(ty, _) | TyKind::Ref(_, ty, _) => Some(ty),
1757                _ => None,
1758            }
1759        }
1760        let target_ty = self.coerce_unsized_look_through_fields(target_ty, for_ptr)?;
1761        let current_ty = self.coerce_unsized_look_through_fields(current_ty, for_ptr)?;
1762
1763        self.unsizing_ptr_from_addr(target_ty, current_ty, addr)
1764    }
1765
1766    /// Adds metadata to the address and create the fat pointer result of the unsizing operation.
1767    fn unsizing_ptr_from_addr(
1768        &mut self,
1769        target_ty: Ty<'db>,
1770        current_ty: Ty<'db>,
1771        addr: Interval,
1772    ) -> Result<'db, IntervalOrOwned> {
1773        use IntervalOrOwned::*;
1774        Ok(match &target_ty.kind() {
1775            TyKind::Slice(_) => match &current_ty.kind() {
1776                TyKind::Array(_, size) => {
1777                    let len = match try_const_usize(self.db, *size) {
1778                        None => {
1779                            not_supported!("unevaluatble len of array in coerce unsized")
1780                        }
1781                        Some(it) => it as usize,
1782                    };
1783                    let mut r = Vec::with_capacity(16);
1784                    let addr = addr.get(self)?;
1785                    r.extend(addr.iter().copied());
1786                    r.extend(len.to_le_bytes());
1787                    Owned(r)
1788                }
1789                t => {
1790                    not_supported!("slice unsizing from non array type {t:?}")
1791                }
1792            },
1793            TyKind::Dynamic(..) => {
1794                let vtable = self.vtable_map.id(current_ty);
1795                let mut r = Vec::with_capacity(16);
1796                let addr = addr.get(self)?;
1797                r.extend(addr.iter().copied());
1798                r.extend(vtable.to_le_bytes());
1799                Owned(r)
1800            }
1801            TyKind::Adt(adt_def, target_subst) => match &current_ty.kind() {
1802                TyKind::Adt(current_adt_def, current_subst) => {
1803                    let id = adt_def.def_id();
1804                    let current_id = current_adt_def.def_id();
1805                    if id != current_id {
1806                        not_supported!("unsizing struct with different type");
1807                    }
1808                    let id = match id {
1809                        AdtId::StructId(s) => s,
1810                        AdtId::UnionId(_) => not_supported!("unsizing unions"),
1811                        AdtId::EnumId(_) => not_supported!("unsizing enums"),
1812                    };
1813                    let Some((last_field, _)) = id.fields(self.db).fields().iter().next_back()
1814                    else {
1815                        not_supported!("unsizing struct without field");
1816                    };
1817                    let target_last_field = self.db.field_types(id.into())[last_field]
1818                        .ty()
1819                        .instantiate(self.interner(), target_subst)
1820                        .skip_norm_wip();
1821                    let current_last_field = self.db.field_types(id.into())[last_field]
1822                        .ty()
1823                        .instantiate(self.interner(), current_subst)
1824                        .skip_norm_wip();
1825                    return self.unsizing_ptr_from_addr(
1826                        target_last_field,
1827                        current_last_field,
1828                        addr,
1829                    );
1830                }
1831                _ => not_supported!("unsizing struct with non adt type"),
1832            },
1833            _ => not_supported!("unknown unsized cast"),
1834        })
1835    }
1836
1837    fn layout_of_variant(
1838        &mut self,
1839        it: VariantId,
1840        subst: GenericArgs<'db>,
1841        locals: &Locals<'a, 'db>,
1842    ) -> Result<'db, (usize, Arc<Layout>, Option<(usize, usize, i128)>)> {
1843        let adt = it.adt_id(self.db);
1844        if let Some(f) = locals.body.owner.as_variant()
1845            && let VariantId::EnumVariantId(it) = it
1846            && let AdtId::EnumId(e) = adt
1847            && f.lookup(self.db).parent == e
1848        {
1849            // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
1850            // infinite sized type errors) we use a dummy layout
1851            let i = self.const_eval_discriminant(it)?;
1852            return Ok((16, self.layout(Ty::new_empty_tuple(self.interner()))?, Some((0, 16, i))));
1853        }
1854        let layout = self.layout_adt(adt, subst)?;
1855        Ok(match &layout.variants {
1856            Variants::Single { .. } | Variants::Empty => (layout.size.bytes_usize(), layout, None),
1857            Variants::Multiple { variants, tag, tag_encoding, .. } => {
1858                let enum_variant_id = match it {
1859                    VariantId::EnumVariantId(it) => it,
1860                    _ => not_supported!("multi variant layout for non-enums"),
1861                };
1862                let mut discriminant = self.const_eval_discriminant(enum_variant_id)?;
1863                let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.index(self.db));
1864                let variant_layout = variants[rustc_enum_variant_idx].clone();
1865                let have_tag = match tag_encoding {
1866                    TagEncoding::Direct => true,
1867                    TagEncoding::Niche { untagged_variant, niche_variants: _, niche_start } => {
1868                        if *untagged_variant == rustc_enum_variant_idx {
1869                            false
1870                        } else {
1871                            discriminant = (variants
1872                                .iter_enumerated()
1873                                .filter(|(it, _)| it != untagged_variant)
1874                                .position(|(it, _)| it == rustc_enum_variant_idx)
1875                                .unwrap() as i128)
1876                                .wrapping_add(*niche_start as i128);
1877                            true
1878                        }
1879                    }
1880                };
1881                (
1882                    layout.size.bytes_usize(),
1883                    Arc::new(variant_layout),
1884                    if have_tag {
1885                        Some((
1886                            layout.fields.offset(0).bytes_usize(),
1887                            tag.size(self.target_data_layout).bytes_usize(),
1888                            discriminant,
1889                        ))
1890                    } else {
1891                        None
1892                    },
1893                )
1894            }
1895        })
1896    }
1897
1898    fn construct_with_layout(
1899        &mut self,
1900        size: usize, // Not necessarily equal to variant_layout.size
1901        variant_layout: &Layout,
1902        tag: Option<(usize, usize, i128)>,
1903        values: impl Iterator<Item = IntervalOrOwned>,
1904    ) -> Result<'db, Vec<u8>> {
1905        let mut result = vec![0; size];
1906        if let Some((offset, size, value)) = tag {
1907            match result.get_mut(offset..offset + size) {
1908                Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),
1909                None => {
1910                    return Err(MirEvalError::InternalError(
1911                        format!(
1912                            "encoded tag ({offset}, {size}, {value}) is out of bounds 0..{size}"
1913                        )
1914                        .into(),
1915                    ));
1916                }
1917            }
1918        }
1919        for (i, op) in values.enumerate() {
1920            let offset = variant_layout.fields.offset(i).bytes_usize();
1921            let op = op.get(self)?;
1922            match result.get_mut(offset..offset + op.len()) {
1923                Some(it) => it.copy_from_slice(op),
1924                None => {
1925                    return Err(MirEvalError::InternalError(
1926                        format!("field offset ({offset}) is out of bounds 0..{size}").into(),
1927                    ));
1928                }
1929            }
1930        }
1931        Ok(result)
1932    }
1933
1934    fn eval_operand(
1935        &mut self,
1936        it: &Operand,
1937        locals: &mut Locals<'a, 'db>,
1938    ) -> Result<'db, Interval> {
1939        Ok(match &it.kind {
1940            OperandKind::Copy(p) | OperandKind::Move(p) => {
1941                locals.drop_flags.remove_place(p.as_ref());
1942                self.eval_place(p, locals)?
1943            }
1944            OperandKind::Static(st) => {
1945                let addr = self.eval_static(*st, locals)?;
1946                Interval::new(addr, self.ptr_size())
1947            }
1948            OperandKind::Constant { konst, .. } => {
1949                self.allocate_const_in_heap(locals, konst.as_ref())?
1950            }
1951            OperandKind::Allocation { allocation } => {
1952                self.allocate_allocation_in_heap(locals, allocation.as_ref())?
1953            }
1954        })
1955    }
1956
1957    fn allocate_valtree_in_heap(
1958        &mut self,
1959        ty: Ty<'db>,
1960        valtree: ValTree<'db>,
1961    ) -> Result<'db, Interval> {
1962        match ty.kind() {
1963            TyKind::Bool => {
1964                let value = valtree.inner().to_leaf().try_to_bool().unwrap();
1965                let addr = self.heap_allocate(1, 1)?;
1966                self.write_memory(addr, &[u8::from(value)])?;
1967                Ok(Interval::new(addr, 1))
1968            }
1969            TyKind::Char => {
1970                let value = valtree.inner().to_leaf().to_u32();
1971                let addr = self.heap_allocate(4, 4)?;
1972                self.write_memory(addr, &value.to_le_bytes())?;
1973                Ok(Interval::new(addr, 4))
1974            }
1975            TyKind::Int(int_ty) => {
1976                let size = int_ty
1977                    .bit_width()
1978                    .map(Size::from_bits)
1979                    .unwrap_or_else(|| Size::from_bytes(self.ptr_size() as u64));
1980                let bytes = size.bytes_usize();
1981
1982                let value = valtree.inner().to_leaf().to_int(size);
1983                let addr = self.heap_allocate(bytes, bytes)?;
1984                self.write_memory(addr, &value.to_le_bytes()[..bytes])?;
1985                Ok(Interval::new(addr, bytes))
1986            }
1987            TyKind::Uint(uint_ty) => {
1988                let size = uint_ty
1989                    .bit_width()
1990                    .map(Size::from_bits)
1991                    .unwrap_or_else(|| Size::from_bytes(self.ptr_size() as u64));
1992                let bytes = size.bytes_usize();
1993
1994                let value = valtree.inner().to_leaf().to_uint(size);
1995                let addr = self.heap_allocate(bytes, bytes)?;
1996                self.write_memory(addr, &value.to_le_bytes()[..bytes])?;
1997                Ok(Interval::new(addr, bytes))
1998            }
1999            TyKind::Float(float_ty) => {
2000                let size = Size::from_bits(float_ty.bit_width());
2001                let bytes = size.bytes_usize();
2002
2003                let value = valtree.inner().to_leaf().to_uint(size);
2004                let addr = self.heap_allocate(bytes, bytes)?;
2005                self.write_memory(addr, &value.to_le_bytes()[..bytes])?;
2006                Ok(Interval::new(addr, bytes))
2007            }
2008            TyKind::RawPtr(..) => {
2009                let size = self.ptr_size();
2010                let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size));
2011                let addr = self.heap_allocate(size, size)?;
2012                self.write_memory(addr, &value.to_le_bytes()[..size])?;
2013                Ok(Interval::new(addr, size))
2014            }
2015            TyKind::Ref(_, inner_ty, _) => match inner_ty.kind() {
2016                TyKind::Str => {
2017                    let bytes = valtree
2018                        .inner()
2019                        .to_branch()
2020                        .iter()
2021                        .map(|konst| match konst.kind() {
2022                            ConstKind::Value(value) => Ok(value.value.inner().to_leaf().to_u8()),
2023                            _ => not_supported!("unsupported const"),
2024                        })
2025                        .collect::<Result<'_, Vec<_>>>()?;
2026                    let bytes_addr = self.heap_allocate(bytes.len(), 1)?;
2027                    self.write_memory(bytes_addr, &bytes)?;
2028                    let ref_addr = self.heap_allocate(self.ptr_size() * 2, self.ptr_size())?;
2029                    self.write_memory(ref_addr, &bytes_addr.to_bytes())?;
2030                    let mut len = [0; 16];
2031                    len[..size_of::<usize>()].copy_from_slice(&bytes.len().to_le_bytes());
2032                    self.write_memory(ref_addr.offset(self.ptr_size()), &len[..self.ptr_size()])?;
2033                    Ok(Interval::new(ref_addr, self.ptr_size() * 2))
2034                }
2035                TyKind::Slice(inner_ty) => {
2036                    let item_layout = self.layout(inner_ty)?;
2037                    let items = valtree
2038                        .inner()
2039                        .to_branch()
2040                        .iter()
2041                        .map(|konst| match konst.kind() {
2042                            ConstKind::Value(value) => {
2043                                self.allocate_valtree_in_heap(value.ty, value.value)
2044                            }
2045                            _ => not_supported!("unsupported const"),
2046                        })
2047                        .collect::<Result<'_, Vec<_>>>()?;
2048                    let item_size = item_layout.size.bytes_usize();
2049                    let items_addr = self.heap_allocate(
2050                        items.len() * item_size,
2051                        item_layout.align.bytes() as usize,
2052                    )?;
2053                    for (i, item) in items.iter().enumerate() {
2054                        self.copy_from_interval(items_addr.offset(i * item_size), *item)?;
2055                    }
2056                    let ref_addr = self.heap_allocate(self.ptr_size() * 2, self.ptr_size())?;
2057                    self.write_memory(ref_addr, &items_addr.to_bytes())?;
2058                    let mut len = [0; 16];
2059                    len[..size_of::<usize>()].copy_from_slice(&items.len().to_le_bytes());
2060                    self.write_memory(ref_addr.offset(self.ptr_size()), &len[..self.ptr_size()])?;
2061                    Ok(Interval::new(ref_addr, self.ptr_size() * 2))
2062                }
2063                TyKind::Dynamic(..) => not_supported!("`dyn Trait` consts not supported yet"),
2064                _ => {
2065                    let inner_addr = self.allocate_valtree_in_heap(inner_ty, valtree)?;
2066                    let ref_addr = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
2067                    self.write_memory(ref_addr, &inner_addr.addr.to_bytes())?;
2068                    Ok(Interval::new(ref_addr, self.ptr_size()))
2069                }
2070            },
2071            TyKind::Adt(_, _) | TyKind::Array(_, _) | TyKind::Tuple(_) => {
2072                not_supported!(
2073                    "ADTs, arrays and tuples are unsupported in consts currently (requires `adt_const_params`)"
2074                )
2075            }
2076            TyKind::Pat(_, _)
2077            | TyKind::Slice(_)
2078            | TyKind::FnDef(_, _)
2079            | TyKind::Foreign(_)
2080            | TyKind::Dynamic(_, _)
2081            | TyKind::UnsafeBinder(..)
2082            | TyKind::FnPtr(..)
2083            | TyKind::Closure(_, _)
2084            | TyKind::CoroutineClosure(_, _)
2085            | TyKind::Coroutine(_, _)
2086            | TyKind::CoroutineWitness(_, _)
2087            | TyKind::Never
2088            | TyKind::Alias(..)
2089            | TyKind::Param(_)
2090            | TyKind::Bound(..)
2091            | TyKind::Placeholder(_)
2092            | TyKind::Infer(_)
2093            | TyKind::Str
2094            | TyKind::Error(_) => not_supported!("unsupported const"),
2095        }
2096    }
2097
2098    fn allocate_const_in_heap(
2099        &mut self,
2100        locals: &Locals<'a, 'db>,
2101        konst: Const<'db>,
2102    ) -> Result<'db, Interval> {
2103        match konst.kind() {
2104            ConstKind::Value(value) => self.allocate_valtree_in_heap(value.ty, value.value),
2105            ConstKind::Unevaluated(UnevaluatedConst { def: const_id, args: subst }) => {
2106                let mut id = const_id.0;
2107                let mut subst = subst;
2108                if let GeneralConstId::ConstId(c) = id {
2109                    let (c, s) = lookup_impl_const(&self.infcx, self.param_env.param_env, c, subst);
2110                    id = GeneralConstId::ConstId(c);
2111                    subst = s;
2112                }
2113                let allocation = match id {
2114                    GeneralConstId::ConstId(const_id) => {
2115                        self.db.const_eval(const_id, subst, Some(self.param_env)).map_err(|e| {
2116                            let name = id.name(self.db);
2117                            MirEvalError::ConstEvalError(name, Box::new(e))
2118                        })?
2119                    }
2120                    GeneralConstId::StaticId(static_id) => {
2121                        self.db.const_eval_static(static_id).map_err(|e| {
2122                            let name = id.name(self.db);
2123                            MirEvalError::ConstEvalError(name, Box::new(e))
2124                        })?
2125                    }
2126                    GeneralConstId::AnonConstId(anon_const_id) => self
2127                        .db
2128                        .anon_const_eval(anon_const_id, subst, Some(self.param_env))
2129                        .map_err(|e| {
2130                            let name = id.name(self.db);
2131                            MirEvalError::ConstEvalError(name, Box::new(e))
2132                        })?,
2133                };
2134                self.allocate_allocation_in_heap(locals, allocation)
2135            }
2136            _ => not_supported!("evaluating unknown const"),
2137        }
2138    }
2139
2140    fn allocate_allocation_in_heap(
2141        &mut self,
2142        locals: &Locals<'a, 'db>,
2143        allocation: Allocation<'db>,
2144    ) -> Result<'db, Interval> {
2145        let AllocationData { ty, memory: ref v, ref memory_map } = *allocation;
2146        let patch_map = memory_map.transform_addresses(|b, align| {
2147            let addr = self.heap_allocate(b.len(), align)?;
2148            self.write_memory(addr, b)?;
2149            Ok(addr.to_usize())
2150        })?;
2151        let (size, align) = self.size_align_of(allocation.ty, locals)?.unwrap_or((v.len(), 1));
2152        let v: Cow<'_, [u8]> = if size != v.len() {
2153            // Handle self enum
2154            if size == 16 && v.len() < 16 {
2155                Cow::Owned(pad16(v, IsSigned::No).to_vec())
2156            } else if size < 16 && v.len() == 16 {
2157                Cow::Borrowed(&v[0..size])
2158            } else {
2159                return Err(MirEvalError::InvalidConst);
2160            }
2161        } else {
2162            Cow::Borrowed(v)
2163        };
2164        let addr = self.heap_allocate(size, align)?;
2165        self.write_memory(addr, &v)?;
2166        self.patch_addresses(
2167            &patch_map,
2168            |bytes| match memory_map {
2169                MemoryMap::Empty | MemoryMap::Simple(_) => {
2170                    Err(MirEvalError::InvalidVTableId(from_bytes!(usize, bytes)))
2171                }
2172                MemoryMap::Complex(cm) => cm.vtable.ty_of_bytes(bytes),
2173            },
2174            addr,
2175            ty,
2176            locals,
2177        )?;
2178        Ok(Interval::new(addr, size))
2179    }
2180
2181    fn eval_place(&mut self, p: &StoredPlace, locals: &Locals<'a, 'db>) -> Result<'db, Interval> {
2182        let addr = self.place_addr(p, locals)?;
2183        Ok(Interval::new(
2184            addr,
2185            self.size_of_sized(self.place_ty(p, locals)?, locals, "type of this place")?,
2186        ))
2187    }
2188
2189    fn read_memory(&self, addr: Address, size: usize) -> Result<'db, &[u8]> {
2190        if size == 0 {
2191            return Ok(&[]);
2192        }
2193        let (mem, pos) = match addr {
2194            Stack(it) => (&self.stack, it),
2195            Heap(it) => (&self.heap, it),
2196            Invalid(it) => {
2197                return Err(MirEvalError::UndefinedBehavior(format!(
2198                    "read invalid memory address {it} with size {size}"
2199                )));
2200            }
2201        };
2202        mem.get(pos..pos + size)
2203            .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_owned()))
2204    }
2205
2206    fn write_memory_using_ref(&mut self, addr: Address, size: usize) -> Result<'db, &mut [u8]> {
2207        let (mem, pos) = match addr {
2208            Stack(it) => (&mut self.stack, it),
2209            Heap(it) => (&mut self.heap, it),
2210            Invalid(it) => {
2211                return Err(MirEvalError::UndefinedBehavior(format!(
2212                    "write invalid memory address {it} with size {size}"
2213                )));
2214            }
2215        };
2216        mem.get_mut(pos..pos + size)
2217            .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory write".to_owned()))
2218    }
2219
2220    fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<'db, ()> {
2221        if r.is_empty() {
2222            return Ok(());
2223        }
2224        self.write_memory_using_ref(addr, r.len())?.copy_from_slice(r);
2225        Ok(())
2226    }
2227
2228    fn copy_from_interval_or_owned(
2229        &mut self,
2230        addr: Address,
2231        r: IntervalOrOwned,
2232    ) -> Result<'db, ()> {
2233        match r {
2234            IntervalOrOwned::Borrowed(r) => self.copy_from_interval(addr, r),
2235            IntervalOrOwned::Owned(r) => self.write_memory(addr, &r),
2236        }
2237    }
2238
2239    fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<'db, ()> {
2240        if r.size == 0 {
2241            return Ok(());
2242        }
2243
2244        let oob = || MirEvalError::UndefinedBehavior("out of bounds memory write".to_owned());
2245
2246        match (addr, r.addr) {
2247            (Stack(dst), Stack(src)) => {
2248                if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
2249                    return Err(oob());
2250                }
2251                self.stack.copy_within(src..src + r.size, dst)
2252            }
2253            (Heap(dst), Heap(src)) => {
2254                if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
2255                    return Err(oob());
2256                }
2257                self.heap.copy_within(src..src + r.size, dst)
2258            }
2259            (Stack(dst), Heap(src)) => {
2260                self.stack
2261                    .get_mut(dst..dst + r.size)
2262                    .ok_or_else(oob)?
2263                    .copy_from_slice(self.heap.get(src..src + r.size).ok_or_else(oob)?);
2264            }
2265            (Heap(dst), Stack(src)) => {
2266                self.heap
2267                    .get_mut(dst..dst + r.size)
2268                    .ok_or_else(oob)?
2269                    .copy_from_slice(self.stack.get(src..src + r.size).ok_or_else(oob)?);
2270            }
2271            _ => {
2272                return Err(MirEvalError::UndefinedBehavior(format!(
2273                    "invalid memory write at address {addr:?}"
2274                )));
2275            }
2276        }
2277
2278        Ok(())
2279    }
2280
2281    fn size_align_of(
2282        &self,
2283        ty: Ty<'db>,
2284        locals: &Locals<'a, 'db>,
2285    ) -> Result<'db, Option<(usize, usize)>> {
2286        if let Some(layout) = self.layout_cache.borrow().get(&ty) {
2287            return Ok(layout
2288                .is_sized()
2289                .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize)));
2290        }
2291        if let Some(f) = locals.body.owner.as_variant()
2292            && let Some((AdtId::EnumId(e), _)) = ty.as_adt()
2293            && f.lookup(self.db).parent == e
2294        {
2295            // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
2296            // infinite sized type errors) we use a dummy size
2297            return Ok(Some((16, 16)));
2298        }
2299        let layout = self.layout(ty);
2300        if self.assert_placeholder_ty_is_unused
2301            && matches!(layout, Err(MirEvalError::LayoutError(LayoutError::HasPlaceholder, _)))
2302        {
2303            return Ok(Some((0, 1)));
2304        }
2305        let layout = layout?;
2306        Ok(layout.is_sized().then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize)))
2307    }
2308
2309    /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should
2310    /// be something that complete this: `error: type {ty} was unsized. {what} should be sized`
2311    fn size_of_sized(
2312        &self,
2313        ty: Ty<'db>,
2314        locals: &Locals<'a, 'db>,
2315        what: &'static str,
2316    ) -> Result<'db, usize> {
2317        match self.size_align_of(ty, locals)? {
2318            Some(it) => Ok(it.0),
2319            None => Err(MirEvalError::TypeIsUnsized(ty.store(), what)),
2320        }
2321    }
2322
2323    /// A version of `self.size_align_of` which returns error if the type is unsized. `what` argument should
2324    /// be something that complete this: `error: type {ty} was unsized. {what} should be sized`
2325    fn size_align_of_sized(
2326        &self,
2327        ty: Ty<'db>,
2328        locals: &Locals<'a, 'db>,
2329        what: &'static str,
2330    ) -> Result<'db, (usize, usize)> {
2331        match self.size_align_of(ty, locals)? {
2332            Some(it) => Ok(it),
2333            None => Err(MirEvalError::TypeIsUnsized(ty.store(), what)),
2334        }
2335    }
2336
2337    fn heap_allocate(&mut self, size: usize, align: usize) -> Result<'db, Address> {
2338        if !align.is_power_of_two() || align > 10000 {
2339            return Err(MirEvalError::UndefinedBehavior(format!("Alignment {align} is invalid")));
2340        }
2341        while !self.heap.len().is_multiple_of(align) {
2342            self.heap.push(0);
2343        }
2344        if size.checked_add(self.heap.len()).is_none_or(|x| x > self.memory_limit) {
2345            return Err(MirEvalError::Panic(format!("Memory allocation of {size} bytes failed")));
2346        }
2347        let pos = self.heap.len();
2348        self.heap.extend(std::iter::repeat_n(0, size));
2349        Ok(Address::Heap(pos))
2350    }
2351
2352    fn detect_fn_trait(&self, def: FunctionId) -> Option<FnTrait> {
2353        let def = Some(def);
2354        if def == self.cached_fn_trait_func {
2355            Some(FnTrait::Fn)
2356        } else if def == self.cached_fn_mut_trait_func {
2357            Some(FnTrait::FnMut)
2358        } else if def == self.cached_fn_once_trait_func {
2359            Some(FnTrait::FnOnce)
2360        } else {
2361            None
2362        }
2363    }
2364
2365    fn create_memory_map(
2366        &self,
2367        bytes: &[u8],
2368        ty: Ty<'db>,
2369        locals: &Locals<'a, 'db>,
2370    ) -> Result<'db, ComplexMemoryMap<'db>> {
2371        fn rec<'a, 'db>(
2372            this: &Evaluator<'a, 'db>,
2373            bytes: &[u8],
2374            ty: Ty<'db>,
2375            locals: &Locals<'a, 'db>,
2376            mm: &mut ComplexMemoryMap<'db>,
2377            stack_depth_limit: usize,
2378        ) -> Result<'db, ()> {
2379            if stack_depth_limit.checked_sub(1).is_none() {
2380                return Err(MirEvalError::StackOverflow);
2381            }
2382            match ty.kind() {
2383                TyKind::Ref(_, t, _) => {
2384                    let size = this.size_align_of(t, locals)?;
2385                    match size {
2386                        Some((size, _)) => {
2387                            let addr_usize = from_bytes!(usize, bytes);
2388                            let bytes =
2389                                this.read_memory(Address::from_usize(addr_usize), size)?.to_vec();
2390                            mm.insert(addr_usize, bytes.clone().into());
2391                            rec(this, &bytes, t, locals, mm, stack_depth_limit - 1)?;
2392                        }
2393                        None => {
2394                            let mut check_inner = None;
2395                            let (addr, meta) = bytes.split_at(bytes.len() / 2);
2396                            let element_size = match t.kind() {
2397                                TyKind::Str => 1,
2398                                TyKind::Slice(t) => {
2399                                    check_inner = Some(t);
2400                                    this.size_of_sized(t, locals, "slice inner type")?
2401                                }
2402                                TyKind::Dynamic(..) => {
2403                                    let t = this.vtable_map.ty_of_bytes(meta)?;
2404                                    check_inner = Some(t);
2405                                    this.size_of_sized(t, locals, "dyn concrete type")?
2406                                }
2407                                _ => return Ok(()),
2408                            };
2409                            let count = match t.kind() {
2410                                TyKind::Dynamic(..) => 1,
2411                                _ => from_bytes!(usize, meta),
2412                            };
2413                            let size = element_size * count;
2414                            let addr = Address::from_bytes(addr)?;
2415                            let b = this.read_memory(addr, size)?;
2416                            mm.insert(addr.to_usize(), b.into());
2417                            if let Some(ty) = check_inner {
2418                                for i in 0..count {
2419                                    let offset = element_size * i;
2420                                    rec(
2421                                        this,
2422                                        &b[offset..offset + element_size],
2423                                        ty,
2424                                        locals,
2425                                        mm,
2426                                        stack_depth_limit - 1,
2427                                    )?;
2428                                }
2429                            }
2430                        }
2431                    }
2432                }
2433                TyKind::Array(inner, len) => {
2434                    let len = match try_const_usize(this.db, len) {
2435                        Some(it) => it as usize,
2436                        None => not_supported!("non evaluatable array len in patching addresses"),
2437                    };
2438                    let size = this.size_of_sized(inner, locals, "inner of array")?;
2439                    for i in 0..len {
2440                        let offset = i * size;
2441                        rec(
2442                            this,
2443                            &bytes[offset..offset + size],
2444                            inner,
2445                            locals,
2446                            mm,
2447                            stack_depth_limit - 1,
2448                        )?;
2449                    }
2450                }
2451                TyKind::Tuple(subst) => {
2452                    let layout = this.layout(ty)?;
2453                    for (id, ty) in subst.iter().enumerate() {
2454                        let offset = layout.fields.offset(id).bytes_usize();
2455                        let size = this.layout(ty)?.size.bytes_usize();
2456                        rec(
2457                            this,
2458                            &bytes[offset..offset + size],
2459                            ty,
2460                            locals,
2461                            mm,
2462                            stack_depth_limit - 1,
2463                        )?;
2464                    }
2465                }
2466                TyKind::Adt(adt, subst) => match adt.def_id() {
2467                    AdtId::StructId(s) => {
2468                        let data = s.fields(this.db);
2469                        let layout = this.layout(ty)?;
2470                        let field_types = this.db.field_types(s.into());
2471                        for (f, _) in data.fields().iter() {
2472                            let offset = layout
2473                                .fields
2474                                .offset(u32::from(f.into_raw()) as usize)
2475                                .bytes_usize();
2476                            let ty = field_types[f]
2477                                .ty()
2478                                .instantiate(this.interner(), subst)
2479                                .skip_norm_wip();
2480                            let size = this.layout(ty)?.size.bytes_usize();
2481                            rec(
2482                                this,
2483                                &bytes[offset..offset + size],
2484                                ty,
2485                                locals,
2486                                mm,
2487                                stack_depth_limit - 1,
2488                            )?;
2489                        }
2490                    }
2491                    AdtId::EnumId(e) => {
2492                        let layout = this.layout(ty)?;
2493                        if let Some((v, l)) = detect_variant_from_bytes(
2494                            &layout,
2495                            this.db,
2496                            this.target_data_layout,
2497                            bytes,
2498                            e,
2499                        ) {
2500                            let data = v.fields(this.db);
2501                            let field_types = this.db.field_types(v.into());
2502                            for (f, _) in data.fields().iter() {
2503                                let offset =
2504                                    l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
2505                                let ty = field_types[f]
2506                                    .ty()
2507                                    .instantiate(this.interner(), subst)
2508                                    .skip_norm_wip();
2509                                let size = this.layout(ty)?.size.bytes_usize();
2510                                rec(
2511                                    this,
2512                                    &bytes[offset..offset + size],
2513                                    ty,
2514                                    locals,
2515                                    mm,
2516                                    stack_depth_limit - 1,
2517                                )?;
2518                            }
2519                        }
2520                    }
2521                    AdtId::UnionId(_) => (),
2522                },
2523                TyKind::Alias(AliasTy { kind: AliasTyKind::Projection { .. }, .. }) => {
2524                    let mut ocx = ObligationCtxt::new(&this.infcx);
2525                    let ty = ocx
2526                        .structurally_normalize_ty(
2527                            &ObligationCause::dummy(),
2528                            this.param_env.param_env,
2529                            ty,
2530                        )
2531                        .map_err(|_| MirEvalError::NotSupported("couldn't normalize".to_owned()))?;
2532
2533                    rec(this, bytes, ty, locals, mm, stack_depth_limit - 1)?;
2534                }
2535                _ => (),
2536            }
2537            Ok(())
2538        }
2539        let mut mm = ComplexMemoryMap::default();
2540        rec(self, bytes, ty, locals, &mut mm, self.stack_depth_limit - 1)?;
2541        Ok(mm)
2542    }
2543
2544    fn patch_addresses(
2545        &mut self,
2546        patch_map: &FxHashMap<usize, usize>,
2547        ty_of_bytes: impl Fn(&[u8]) -> Result<'db, Ty<'db>> + Copy,
2548        addr: Address,
2549        ty: Ty<'db>,
2550        locals: &Locals<'a, 'db>,
2551    ) -> Result<'db, ()> {
2552        let layout = self.layout(ty)?;
2553        let my_size = self.size_of_sized(ty, locals, "value to patch address")?;
2554        use rustc_type_ir::TyKind;
2555        match ty.kind() {
2556            TyKind::Ref(_, t, _) => {
2557                let size = self.size_align_of(t, locals)?;
2558                match size {
2559                    Some(_) => {
2560                        let current = from_bytes!(usize, self.read_memory(addr, my_size)?);
2561                        let patched = match patch_map.get(&current) {
2562                            Some(it) => {
2563                                self.write_memory(addr, &it.to_le_bytes())?;
2564                                *it
2565                            }
2566                            None => current,
2567                        };
2568                        self.patch_addresses(
2569                            patch_map,
2570                            ty_of_bytes,
2571                            Address::from_usize(patched),
2572                            t,
2573                            locals,
2574                        )?;
2575                    }
2576                    None => {
2577                        let bytes = self.read_memory(addr, my_size)?;
2578                        let (current, metadata) = bytes.split_at(my_size / 2);
2579                        let metadata = metadata.to_vec();
2580                        let current = from_bytes!(usize, current);
2581                        let patched = match patch_map.get(&current) {
2582                            Some(it) => {
2583                                self.write_memory(addr, &it.to_le_bytes())?;
2584                                *it
2585                            }
2586                            None => current,
2587                        };
2588                        let patched = Address::from_usize(patched);
2589                        if let TyKind::Slice(inner) = t.kind() {
2590                            let len = from_bytes!(usize, metadata);
2591                            let size = self.size_of_sized(inner, locals, "slice item to patch")?;
2592                            for i in 0..len {
2593                                self.patch_addresses(
2594                                    patch_map,
2595                                    ty_of_bytes,
2596                                    patched.offset(i * size),
2597                                    inner,
2598                                    locals,
2599                                )?;
2600                            }
2601                        }
2602                    }
2603                }
2604            }
2605            TyKind::FnPtr(_, _) => {
2606                let ty = ty_of_bytes(self.read_memory(addr, my_size)?)?;
2607                let new_id = self.vtable_map.id(ty);
2608                self.write_memory(addr, &new_id.to_le_bytes())?;
2609            }
2610            TyKind::Adt(id, args) => match id.def_id() {
2611                AdtId::StructId(s) => {
2612                    for (i, (_, field)) in self.db.field_types(s.into()).iter().enumerate() {
2613                        let offset = layout.fields.offset(i).bytes_usize();
2614                        let ty = field.ty().instantiate(self.interner(), args).skip_norm_wip();
2615                        self.patch_addresses(
2616                            patch_map,
2617                            ty_of_bytes,
2618                            addr.offset(offset),
2619                            ty,
2620                            locals,
2621                        )?;
2622                    }
2623                }
2624                AdtId::UnionId(_) => (),
2625                AdtId::EnumId(e) => {
2626                    if let Some((ev, layout)) = detect_variant_from_bytes(
2627                        &layout,
2628                        self.db,
2629                        self.target_data_layout,
2630                        self.read_memory(addr, layout.size.bytes_usize())?,
2631                        e,
2632                    ) {
2633                        for (i, (_, field)) in self.db.field_types(ev.into()).iter().enumerate() {
2634                            let offset = layout.fields.offset(i).bytes_usize();
2635                            let ty = field.ty().instantiate(self.interner(), args).skip_norm_wip();
2636                            self.patch_addresses(
2637                                patch_map,
2638                                ty_of_bytes,
2639                                addr.offset(offset),
2640                                ty,
2641                                locals,
2642                            )?;
2643                        }
2644                    }
2645                }
2646            },
2647            TyKind::Tuple(tys) => {
2648                for (id, ty) in tys.iter().enumerate() {
2649                    let offset = layout.fields.offset(id).bytes_usize();
2650                    self.patch_addresses(patch_map, ty_of_bytes, addr.offset(offset), ty, locals)?;
2651                }
2652            }
2653            TyKind::Array(inner, len) => {
2654                let len = match consteval::try_const_usize(self.db, len) {
2655                    Some(it) => it as usize,
2656                    None => not_supported!("non evaluatable array len in patching addresses"),
2657                };
2658                let size = self.size_of_sized(inner, locals, "inner of array")?;
2659                for i in 0..len {
2660                    self.patch_addresses(
2661                        patch_map,
2662                        ty_of_bytes,
2663                        addr.offset(i * size),
2664                        inner,
2665                        locals,
2666                    )?;
2667                }
2668            }
2669            TyKind::Bool
2670            | TyKind::Char
2671            | TyKind::Int(_)
2672            | TyKind::Uint(_)
2673            | TyKind::Float(_)
2674            | TyKind::Slice(_)
2675            | TyKind::RawPtr(_, _)
2676            | TyKind::FnDef(_, _)
2677            | TyKind::Str
2678            | TyKind::Never
2679            | TyKind::Closure(_, _)
2680            | TyKind::Coroutine(_, _)
2681            | TyKind::CoroutineWitness(_, _)
2682            | TyKind::Foreign(_)
2683            | TyKind::Error(_)
2684            | TyKind::Placeholder(_)
2685            | TyKind::Dynamic(_, _)
2686            | TyKind::Alias(..)
2687            | TyKind::Bound(_, _)
2688            | TyKind::Infer(_)
2689            | TyKind::Pat(_, _)
2690            | TyKind::Param(_)
2691            | TyKind::UnsafeBinder(_)
2692            | TyKind::CoroutineClosure(_, _) => (),
2693        }
2694        Ok(())
2695    }
2696
2697    fn exec_fn_pointer(
2698        &mut self,
2699        bytes: Interval,
2700        destination: Interval,
2701        args: &[IntervalAndTy<'db>],
2702        locals: &Locals<'a, 'db>,
2703        target_bb: Option<BasicBlockId>,
2704        span: MirSpan,
2705    ) -> Result<'db, Option<StackFrame<'a, 'db>>> {
2706        let id = from_bytes!(usize, bytes.get(self)?);
2707        let next_ty = self.vtable_map.ty(id)?;
2708        use rustc_type_ir::TyKind;
2709        match next_ty.kind() {
2710            TyKind::FnDef(def, generic_args) => {
2711                self.exec_fn_def(def.0, generic_args, destination, args, locals, target_bb, span)
2712            }
2713            TyKind::Closure(id, generic_args) => self.exec_closure(
2714                id.0,
2715                bytes.slice(0..0),
2716                generic_args,
2717                destination,
2718                args,
2719                locals,
2720                span,
2721            ),
2722            _ => Err(MirEvalError::InternalError("function pointer to non function".into())),
2723        }
2724    }
2725
2726    fn exec_closure(
2727        &mut self,
2728        closure: InternedClosureId<'db>,
2729        closure_data: Interval,
2730        generic_args: GenericArgs<'db>,
2731        destination: Interval,
2732        args: &[IntervalAndTy<'db>],
2733        locals: &Locals<'a, 'db>,
2734        span: MirSpan,
2735    ) -> Result<'db, Option<StackFrame<'a, 'db>>> {
2736        let mir_body = self
2737            .db
2738            .monomorphized_mir_body_for_closure(
2739                closure,
2740                generic_args.store(),
2741                self.param_env.store(),
2742            )
2743            .map_err(|it| MirEvalError::MirLowerErrorForClosure(closure, it))?;
2744        let closure_data =
2745            if mir_body.locals[mir_body.param_locals[0]].ty.as_ref().as_reference().is_some() {
2746                closure_data.addr.to_bytes().to_vec()
2747            } else {
2748                closure_data.get(self)?.to_owned()
2749            };
2750        let arg_bytes = iter::once(Ok(closure_data))
2751            .chain(args.iter().map(|it| Ok(it.get(self)?.to_owned())))
2752            .collect::<Result<'db, Vec<_>>>()?;
2753        let interval = self
2754            .interpret_mir(mir_body, arg_bytes.into_iter().map(IntervalOrOwned::Owned))
2755            .map_err(|e| {
2756                MirEvalError::InFunction(
2757                    Box::new(e),
2758                    vec![(Either::Right(closure), span, locals.body.owner)],
2759                )
2760            })?;
2761        destination.write_from_interval(self, interval)?;
2762        Ok(None)
2763    }
2764
2765    fn exec_fn_def(
2766        &mut self,
2767        def: CallableDefId,
2768        generic_args: GenericArgs<'db>,
2769        destination: Interval,
2770        args: &[IntervalAndTy<'db>],
2771        locals: &Locals<'a, 'db>,
2772        target_bb: Option<BasicBlockId>,
2773        span: MirSpan,
2774    ) -> Result<'db, Option<StackFrame<'a, 'db>>> {
2775        match def {
2776            CallableDefId::FunctionId(def) => {
2777                if self.detect_fn_trait(def).is_some() {
2778                    return self.exec_fn_trait(
2779                        def,
2780                        args,
2781                        generic_args,
2782                        locals,
2783                        destination,
2784                        target_bb,
2785                        span,
2786                    );
2787                }
2788                self.exec_fn_with_args(
2789                    def,
2790                    args,
2791                    generic_args,
2792                    locals,
2793                    destination,
2794                    target_bb,
2795                    span,
2796                )
2797            }
2798            CallableDefId::StructId(id) => {
2799                let (size, variant_layout, tag) =
2800                    self.layout_of_variant(id.into(), generic_args, locals)?;
2801                let result = self.construct_with_layout(
2802                    size,
2803                    &variant_layout,
2804                    tag,
2805                    args.iter().map(|it| it.interval.into()),
2806                )?;
2807                destination.write_from_bytes(self, &result)?;
2808                Ok(None)
2809            }
2810            CallableDefId::EnumVariantId(id) => {
2811                let (size, variant_layout, tag) =
2812                    self.layout_of_variant(id.into(), generic_args, locals)?;
2813                let result = self.construct_with_layout(
2814                    size,
2815                    &variant_layout,
2816                    tag,
2817                    args.iter().map(|it| it.interval.into()),
2818                )?;
2819                destination.write_from_bytes(self, &result)?;
2820                Ok(None)
2821            }
2822        }
2823    }
2824
2825    fn get_mir_or_dyn_index(
2826        &self,
2827        def: FunctionId,
2828        generic_args: GenericArgs<'db>,
2829        locals: &Locals<'a, 'db>,
2830        span: MirSpan,
2831    ) -> Result<'db, MirOrDynIndex<'db>> {
2832        let pair = (def, generic_args);
2833        if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) {
2834            return Ok(r.clone());
2835        }
2836        let (def, generic_args) = pair;
2837        let r = if let Some(self_ty_idx) =
2838            is_dyn_method(self.interner(), self.param_env.param_env, def, generic_args)
2839        {
2840            MirOrDynIndex::Dyn(self_ty_idx)
2841        } else {
2842            let (imp, generic_args) = self.db.lookup_impl_method(
2843                ParamEnvAndCrate { param_env: self.param_env.param_env, krate: self.crate_id },
2844                def,
2845                generic_args,
2846            );
2847            let Either::Left(imp) = imp else {
2848                not_supported!("evaluating builtin derive impls is not supported")
2849            };
2850
2851            let mir_body = self
2852                .db
2853                .monomorphized_mir_body(imp.into(), generic_args.store(), self.param_env.store())
2854                .map_err(|e| {
2855                    MirEvalError::InFunction(
2856                        Box::new(MirEvalError::MirLowerError(imp, e)),
2857                        vec![(Either::Left(imp), span, locals.body.owner)],
2858                    )
2859                })?;
2860            MirOrDynIndex::Mir(mir_body)
2861        };
2862        self.mir_or_dyn_index_cache.borrow_mut().insert((def, generic_args), r.clone());
2863        Ok(r)
2864    }
2865
2866    fn exec_fn_with_args(
2867        &mut self,
2868        mut def: FunctionId,
2869        args: &[IntervalAndTy<'db>],
2870        generic_args: GenericArgs<'db>,
2871        locals: &Locals<'a, 'db>,
2872        destination: Interval,
2873        target_bb: Option<BasicBlockId>,
2874        span: MirSpan,
2875    ) -> Result<'db, Option<StackFrame<'a, 'db>>> {
2876        if self.detect_and_exec_special_function(
2877            def,
2878            args,
2879            generic_args,
2880            locals,
2881            destination,
2882            span,
2883        )? {
2884            return Ok(None);
2885        }
2886        if let Some(redirect_def) = self.detect_and_redirect_special_function(def)? {
2887            def = redirect_def;
2888        }
2889        let arg_bytes = args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval));
2890        match self.get_mir_or_dyn_index(def, generic_args, locals, span)? {
2891            MirOrDynIndex::Dyn(self_ty_idx) => {
2892                // In the layout of current possible receiver, which at the moment of writing this code is one of
2893                // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible receivers,
2894                // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on
2895                // the type.
2896                let first_arg = arg_bytes.clone().next().unwrap();
2897                let first_arg = first_arg.get(self)?;
2898                let ty = self
2899                    .vtable_map
2900                    .ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?;
2901                let mut args_for_target = args.to_vec();
2902                args_for_target[0] = IntervalAndTy {
2903                    interval: args_for_target[0].interval.slice(0..self.ptr_size()),
2904                    ty,
2905                };
2906                let generics_for_target = GenericArgs::new_from_iter(
2907                    self.interner(),
2908                    generic_args
2909                        .iter()
2910                        .enumerate()
2911                        .map(|(i, it)| if i == self_ty_idx { ty.into() } else { it }),
2912                );
2913                self.exec_fn_with_args(
2914                    def,
2915                    &args_for_target,
2916                    generics_for_target,
2917                    locals,
2918                    destination,
2919                    target_bb,
2920                    span,
2921                )
2922            }
2923            MirOrDynIndex::Mir(body) => self.exec_looked_up_function(
2924                body,
2925                locals,
2926                def,
2927                arg_bytes,
2928                span,
2929                destination,
2930                target_bb,
2931            ),
2932        }
2933    }
2934
2935    fn exec_looked_up_function(
2936        &mut self,
2937        mir_body: &'db MirBody<'db>,
2938        locals: &Locals<'a, 'db>,
2939        def: FunctionId,
2940        arg_bytes: impl Iterator<Item = IntervalOrOwned>,
2941        span: MirSpan,
2942        destination: Interval,
2943        target_bb: Option<BasicBlockId>,
2944    ) -> Result<'db, Option<StackFrame<'a, 'db>>> {
2945        if let Some(target_bb) = target_bb {
2946            let (mut locals, prev_stack_ptr) =
2947                self.create_locals_for_body(mir_body, Some(destination))?;
2948            self.fill_locals_for_body(mir_body, &mut locals, arg_bytes.into_iter())?;
2949            let span = (span, locals.body.owner);
2950            Ok(Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span }))
2951        } else {
2952            let result = self.interpret_mir(mir_body, arg_bytes).map_err(|e| {
2953                MirEvalError::InFunction(
2954                    Box::new(e),
2955                    vec![(Either::Left(def), span, locals.body.owner)],
2956                )
2957            })?;
2958            destination.write_from_interval(self, result)?;
2959            Ok(None)
2960        }
2961    }
2962
2963    fn exec_fn_trait(
2964        &mut self,
2965        def: FunctionId,
2966        args: &[IntervalAndTy<'db>],
2967        generic_args: GenericArgs<'db>,
2968        locals: &Locals<'a, 'db>,
2969        destination: Interval,
2970        target_bb: Option<BasicBlockId>,
2971        span: MirSpan,
2972    ) -> Result<'db, Option<StackFrame<'a, 'db>>> {
2973        let func = args
2974            .first()
2975            .ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?;
2976        let mut func_ty = func.ty;
2977        let mut func_data = func.interval;
2978        while let TyKind::Ref(_, z, _) = func_ty.kind() {
2979            func_ty = z;
2980            if matches!(func_ty.kind(), TyKind::Dynamic(..)) {
2981                let id =
2982                    from_bytes!(usize, &func_data.get(self)?[self.ptr_size()..self.ptr_size() * 2]);
2983                func_data = func_data.slice(0..self.ptr_size());
2984                func_ty = self.vtable_map.ty(id)?;
2985            }
2986            let size = self.size_of_sized(func_ty, locals, "self type of fn trait")?;
2987            func_data = Interval { addr: Address::from_bytes(func_data.get(self)?)?, size };
2988        }
2989        match func_ty.kind() {
2990            TyKind::FnDef(def, subst) => {
2991                self.exec_fn_def(def.0, subst, destination, &args[1..], locals, target_bb, span)
2992            }
2993            TyKind::FnPtr(..) => {
2994                self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span)
2995            }
2996            TyKind::Closure(closure, subst) => self.exec_closure(
2997                closure.0,
2998                func_data,
2999                GenericArgs::new_from_slice(subst.as_closure().parent_args()),
3000                destination,
3001                &args[1..],
3002                locals,
3003                span,
3004            ),
3005            _ => {
3006                // try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
3007                let arg0 = func;
3008                let args = &args[1..];
3009                let arg1 = {
3010                    let ty = Ty::new_tup_from_iter(self.interner(), args.iter().map(|it| it.ty));
3011                    let layout = self.layout(ty)?;
3012                    let result = self.construct_with_layout(
3013                        layout.size.bytes_usize(),
3014                        &layout,
3015                        None,
3016                        args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval)),
3017                    )?;
3018                    // FIXME: there is some leak here
3019                    let size = layout.size.bytes_usize();
3020                    let addr = self.heap_allocate(size, layout.align.bytes() as usize)?;
3021                    self.write_memory(addr, &result)?;
3022                    IntervalAndTy { interval: Interval { addr, size }, ty }
3023                };
3024                self.exec_fn_with_args(
3025                    def,
3026                    &[arg0.clone(), arg1],
3027                    generic_args,
3028                    locals,
3029                    destination,
3030                    target_bb,
3031                    span,
3032                )
3033            }
3034        }
3035    }
3036
3037    fn eval_static(&mut self, st: StaticId, locals: &Locals<'a, 'db>) -> Result<'db, Address> {
3038        if let Some(o) = self.static_locations.get(&st) {
3039            return Ok(*o);
3040        };
3041        let static_data = StaticSignature::of(self.db, st);
3042        let result = if !static_data.flags.contains(StaticFlags::EXTERN) {
3043            let allocation = self.db.const_eval_static(st).map_err(|e| {
3044                MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e))
3045            })?;
3046            self.allocate_allocation_in_heap(locals, allocation)?
3047        } else {
3048            let ty = InferenceResult::of(self.db, DefWithBodyId::from(st))
3049                .expr_ty(Body::of(self.db, st.into()).root_expr());
3050            let Some((size, align)) = self.size_align_of(ty, locals)? else {
3051                not_supported!("unsized extern static");
3052            };
3053            let addr = self.heap_allocate(size, align)?;
3054            Interval::new(addr, size)
3055        };
3056        let addr = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
3057        self.write_memory(addr, &result.addr.to_bytes())?;
3058        self.static_locations.insert(st, addr);
3059        Ok(addr)
3060    }
3061
3062    fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> {
3063        let r = self.db.const_eval_discriminant(variant);
3064        match r {
3065            Ok(r) => Ok(r),
3066            Err(e) => {
3067                let db = self.db;
3068                let loc = variant.lookup(db);
3069                let edition = self.crate_id.data(self.db).edition;
3070                let name = format!(
3071                    "{}::{}",
3072                    EnumSignature::of(self.db, loc.parent).name.display(db, edition),
3073                    loc.parent
3074                        .enum_variants(self.db)
3075                        .variant_name_by_id(variant)
3076                        .unwrap()
3077                        .display(db, edition),
3078                );
3079                Err(MirEvalError::ConstEvalError(name, Box::new(e)))
3080            }
3081        }
3082    }
3083
3084    fn drop_place(
3085        &mut self,
3086        place: &StoredPlace,
3087        locals: &mut Locals<'a, 'db>,
3088        span: MirSpan,
3089    ) -> Result<'db, ()> {
3090        let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
3091        if !locals.drop_flags.remove_place(place.as_ref()) {
3092            return Ok(());
3093        }
3094        let metadata = match metadata {
3095            Some(it) => it.get(self)?.to_vec(),
3096            None => vec![],
3097        };
3098        self.run_drop_glue_deep(ty, locals, addr, &metadata, span)
3099    }
3100
3101    fn run_drop_glue_deep(
3102        &mut self,
3103        ty: Ty<'db>,
3104        locals: &Locals<'a, 'db>,
3105        addr: Address,
3106        metadata: &[u8],
3107        span: MirSpan,
3108    ) -> Result<'db, ()> {
3109        let Some(drop_fn) = self.lang_items().Drop_drop else {
3110            // in some tests we don't have drop trait in minicore, and
3111            // we can ignore drop in them.
3112            return Ok(());
3113        };
3114
3115        let generic_args = GenericArgs::new_from_slice(&[ty.into()]);
3116        let (drop_impl, drop_args) = self.db.lookup_impl_method(
3117            ParamEnvAndCrate { param_env: self.param_env.param_env, krate: self.crate_id },
3118            drop_fn,
3119            generic_args,
3120        );
3121        if let Either::Left(drop_impl) = drop_impl
3122            && matches!(drop_impl.lookup(self.db).container, ItemContainerId::ImplId(_))
3123            && let Ok(body) = self.db.monomorphized_mir_body(
3124                drop_impl.into(),
3125                drop_args.store(),
3126                self.param_env.store(),
3127            )
3128        {
3129            self.exec_looked_up_function(
3130                body,
3131                locals,
3132                drop_impl,
3133                iter::once(IntervalOrOwned::Owned(addr.to_bytes().to_vec())),
3134                span,
3135                Interval { addr: Address::Invalid(0), size: 0 },
3136                None,
3137            )?;
3138        }
3139        match ty.kind() {
3140            TyKind::Adt(adt_def, subst) => {
3141                let id = adt_def.def_id();
3142                match id {
3143                    AdtId::StructId(s) => {
3144                        let data = StructSignature::of(self.db, s);
3145                        if data.flags.contains(StructFlags::IS_MANUALLY_DROP) {
3146                            return Ok(());
3147                        }
3148                        let layout = self.layout_adt(id, subst)?;
3149                        let variant_fields = s.fields(self.db);
3150                        match variant_fields.shape {
3151                            FieldsShape::Record | FieldsShape::Tuple => {
3152                                let field_types = self.db.field_types(s.into());
3153                                for (field, _) in variant_fields.fields().iter() {
3154                                    let offset = layout
3155                                        .fields
3156                                        .offset(u32::from(field.into_raw()) as usize)
3157                                        .bytes_usize();
3158                                    let addr = addr.offset(offset);
3159                                    let ty = field_types[field]
3160                                        .ty()
3161                                        .instantiate(self.interner(), subst)
3162                                        .skip_norm_wip();
3163                                    self.run_drop_glue_deep(ty, locals, addr, &[], span)?;
3164                                }
3165                            }
3166                            FieldsShape::Unit => (),
3167                        }
3168                    }
3169                    AdtId::UnionId(_) => (), // union fields don't need drop
3170                    AdtId::EnumId(_) => (),
3171                }
3172            }
3173            TyKind::Dynamic(..) => {
3174                if !metadata.is_empty() {
3175                    let concrete_ty = self.vtable_map.ty_of_bytes(metadata)?;
3176                    self.run_drop_glue_deep(concrete_ty, locals, addr, &[], span)?;
3177                }
3178            }
3179            TyKind::Bool
3180            | TyKind::Char
3181            | TyKind::Int(_)
3182            | TyKind::Uint(_)
3183            | TyKind::Float(_)
3184            | TyKind::Tuple(_)
3185            | TyKind::Array(_, _)
3186            | TyKind::Slice(_)
3187            | TyKind::RawPtr(_, _)
3188            | TyKind::Ref(_, _, _)
3189            | TyKind::Alias(..)
3190            | TyKind::FnDef(_, _)
3191            | TyKind::Str
3192            | TyKind::Never
3193            | TyKind::Closure(_, _)
3194            | TyKind::Coroutine(_, _)
3195            | TyKind::CoroutineClosure(..)
3196            | TyKind::CoroutineWitness(_, _)
3197            | TyKind::Foreign(_)
3198            | TyKind::Error(_)
3199            | TyKind::Param(_)
3200            | TyKind::Placeholder(_)
3201            | TyKind::FnPtr(..)
3202            | TyKind::Bound(..)
3203            | TyKind::Infer(..)
3204            | TyKind::Pat(..)
3205            | TyKind::UnsafeBinder(..) => (),
3206        };
3207        Ok(())
3208    }
3209
3210    fn write_to_stdout(&mut self, interval: Interval) -> Result<'db, ()> {
3211        self.stdout.extend(interval.get(self)?.to_vec());
3212        Ok(())
3213    }
3214
3215    fn write_to_stderr(&mut self, interval: Interval) -> Result<'db, ()> {
3216        self.stderr.extend(interval.get(self)?.to_vec());
3217        Ok(())
3218    }
3219}
3220
3221pub fn render_const_using_debug_impl<'db>(
3222    db: &'db dyn HirDatabase,
3223    owner: InferBodyId<'db>,
3224    c: Allocation<'db>,
3225    ty: Ty<'db>,
3226) -> Result<'db, String> {
3227    let mut evaluator = Evaluator::new(db, owner, false, None)?;
3228    let locals = &Locals {
3229        ptr: ArenaMap::new(),
3230        body: db
3231            .mir_body(owner)
3232            .map_err(|_| MirEvalError::NotSupported("unreachable".to_owned()))?,
3233        drop_flags: DropFlags::default(),
3234    };
3235    let data = evaluator.allocate_allocation_in_heap(locals, c)?;
3236    let lang_items = evaluator.interner().lang_items();
3237    let resolver = owner.resolver(db);
3238    let Some(debug_fmt_fn) = lang_items.Debug_fmt else {
3239        not_supported!("core::fmt::Debug::fmt not found");
3240    };
3241    let ptr_size = evaluator.ptr_size();
3242    // Construct the arguments of `format_args!("{:?}", THE_CONST)` directly in memory and hand
3243    // them to `std::fmt::format`.
3244    //
3245    // `core::fmt::rt::Argument` is a niche-encoded `Placeholder { value: NonNull<()>, formatter }`,
3246    // i.e. two words: a pointer to the value, and the type-erased `<T as Debug>::fmt` function.
3247    // A non-null `value` is what distinguishes the `Placeholder` variant from `Count`.
3248    let argument = evaluator.heap_allocate(ptr_size * 2, ptr_size)?;
3249    evaluator.write_memory(argument, &data.addr.to_bytes())?;
3250    let debug_fmt_fn_ptr = evaluator.vtable_map.id(Ty::new_fn_def(
3251        evaluator.interner(),
3252        CallableDefId::FunctionId(debug_fmt_fn).into(),
3253        GenericArgs::new_from_slice(&[ty.into()]),
3254    ));
3255    evaluator.write_memory(argument.offset(ptr_size), &debug_fmt_fn_ptr.to_le_bytes())?;
3256    // Since Rust 1.93 `core::fmt::Arguments` is two words wide:
3257    //   struct Arguments<'a> { template: NonNull<u8>, args: NonNull<Argument<'a>> }
3258    // `template` points at a byte-encoded format string; `format_args!("{:?}", x)` encodes to a
3259    // single default placeholder (`0xC0`) followed by the end marker (`0x00`). `args` points at
3260    // our one-element argument array, and must stay pointer-aligned: `core` uses the low bit of
3261    // `args` as a tag (1 = inline `&str` form, 0 = placeholder form), and heap allocations here
3262    // are pointer-aligned so the bit is 0 as required.
3263    let template = evaluator.heap_allocate(2, 1)?;
3264    evaluator.write_memory(template, &[0xC0, 0x00])?;
3265    let arguments = evaluator.heap_allocate(ptr_size * 2, ptr_size)?;
3266    evaluator.write_memory(arguments, &template.to_bytes())?;
3267    evaluator.write_memory(arguments.offset(ptr_size), &argument.to_bytes())?;
3268    let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
3269        db,
3270        &hir_def::expr_store::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
3271        HygieneId::ROOT,
3272    ) else {
3273        not_supported!("std::fmt::format not found");
3274    };
3275    let interval = evaluator.interpret_mir(
3276        db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?,
3277        [IntervalOrOwned::Borrowed(Interval { addr: arguments, size: ptr_size * 2 })].into_iter(),
3278    )?;
3279    let message_string = interval.get(&evaluator)?;
3280    let words = [
3281        from_bytes!(usize, message_string[0..ptr_size]),
3282        from_bytes!(usize, message_string[ptr_size..2 * ptr_size]),
3283        from_bytes!(usize, message_string[2 * ptr_size..3 * ptr_size]),
3284    ];
3285    let Some(addr) = words.into_iter().map(Address::from_usize).find(|it| matches!(it, Heap(_)))
3286    else {
3287        // No heap buffer means the formatted string is empty.
3288        return Ok(String::new());
3289    };
3290    let size = words
3291        .into_iter()
3292        .filter(|&it| !matches!(Address::from_usize(it), Heap(_)))
3293        .min()
3294        .unwrap_or(0);
3295    Ok(std::string::String::from_utf8_lossy(evaluator.read_memory(addr, size)?).into_owned())
3296}
3297
3298#[derive(PartialEq, Eq)]
3299pub enum IsSigned {
3300    Yes,
3301    No,
3302}
3303
3304impl From<bool> for IsSigned {
3305    fn from(value: bool) -> Self {
3306        if value { Self::Yes } else { Self::No }
3307    }
3308}
3309
3310pub fn pad16(it: &[u8], is_signed: IsSigned) -> [u8; 16] {
3311    let is_negative = is_signed == IsSigned::Yes && it.last().unwrap_or(&0) > &127;
3312    let mut res = [if is_negative { 255 } else { 0 }; 16];
3313    res[..it.len()].copy_from_slice(it);
3314    res
3315}
3316
3317macro_rules! for_each_int_type {
3318    ($call_macro:path, $args:tt) => {
3319        $call_macro! {
3320            $args
3321            I8
3322            U8
3323            I16
3324            U16
3325            I32
3326            U32
3327            I64
3328            U64
3329            I128
3330            U128
3331        }
3332    };
3333}
3334
3335#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
3336enum IntValue {
3337    I8(i8),
3338    U8(u8),
3339    I16(i16),
3340    U16(u16),
3341    I32(i32),
3342    U32(u32),
3343    I64(i64),
3344    U64(u64),
3345    I128(i128),
3346    U128(u128),
3347}
3348
3349macro_rules! checked_int_op {
3350    ( [ $op:ident ] $( $int_ty:ident )+ ) => {
3351        fn $op(self, other: Self) -> Option<Self> {
3352            match (self, other) {
3353                $( (Self::$int_ty(a), Self::$int_ty(b)) => a.$op(b).map(Self::$int_ty), )+
3354                _ => panic!("incompatible integer types"),
3355            }
3356        }
3357    };
3358}
3359
3360macro_rules! int_bit_shifts {
3361    ( [ $op:ident ] $( $int_ty:ident )+ ) => {
3362        fn $op(self, amount: u32) -> Option<Self> {
3363            match self {
3364                $( Self::$int_ty(this) => this.$op(amount).map(Self::$int_ty), )+
3365            }
3366        }
3367    };
3368}
3369
3370macro_rules! unchecked_int_op {
3371    ( [ $name:ident, $op:tt ]  $( $int_ty:ident )+ ) => {
3372        fn $name(self, other: Self) -> Self {
3373            match (self, other) {
3374                $( (Self::$int_ty(a), Self::$int_ty(b)) => Self::$int_ty(a $op b), )+
3375                _ => panic!("incompatible integer types"),
3376            }
3377        }
3378    };
3379}
3380
3381impl IntValue {
3382    fn from_bytes(bytes: &[u8], is_signed: bool) -> Self {
3383        match (bytes.len(), is_signed) {
3384            (1, false) => Self::U8(u8::from_le_bytes(bytes.try_into().unwrap())),
3385            (1, true) => Self::I8(i8::from_le_bytes(bytes.try_into().unwrap())),
3386            (2, false) => Self::U16(u16::from_le_bytes(bytes.try_into().unwrap())),
3387            (2, true) => Self::I16(i16::from_le_bytes(bytes.try_into().unwrap())),
3388            (4, false) => Self::U32(u32::from_le_bytes(bytes.try_into().unwrap())),
3389            (4, true) => Self::I32(i32::from_le_bytes(bytes.try_into().unwrap())),
3390            (8, false) => Self::U64(u64::from_le_bytes(bytes.try_into().unwrap())),
3391            (8, true) => Self::I64(i64::from_le_bytes(bytes.try_into().unwrap())),
3392            (16, false) => Self::U128(u128::from_le_bytes(bytes.try_into().unwrap())),
3393            (16, true) => Self::I128(i128::from_le_bytes(bytes.try_into().unwrap())),
3394            (len, is_signed) => {
3395                never!("invalid integer size: {len}, signed: {is_signed}");
3396                Self::I32(0)
3397            }
3398        }
3399    }
3400
3401    fn to_bytes(self) -> Vec<u8> {
3402        macro_rules! m {
3403            ( [] $( $int_ty:ident )+ ) => {
3404                match self {
3405                    $( Self::$int_ty(v) => v.to_le_bytes().to_vec() ),+
3406                }
3407            };
3408        }
3409        for_each_int_type! { m, [] }
3410    }
3411
3412    fn as_u32(self) -> Option<u32> {
3413        macro_rules! m {
3414            ( [] $( $int_ty:ident )+ ) => {
3415                match self {
3416                    $( Self::$int_ty(v) => v.try_into().ok() ),+
3417                }
3418            };
3419        }
3420        for_each_int_type! { m, [] }
3421    }
3422
3423    for_each_int_type!(checked_int_op, [checked_add]);
3424    for_each_int_type!(checked_int_op, [checked_sub]);
3425    for_each_int_type!(checked_int_op, [checked_div]);
3426    for_each_int_type!(checked_int_op, [checked_rem]);
3427    for_each_int_type!(checked_int_op, [checked_mul]);
3428
3429    for_each_int_type!(int_bit_shifts, [checked_shl]);
3430    for_each_int_type!(int_bit_shifts, [checked_shr]);
3431}
3432
3433impl std::ops::BitAnd for IntValue {
3434    type Output = Self;
3435    for_each_int_type!(unchecked_int_op, [bitand, &]);
3436}
3437impl std::ops::BitOr for IntValue {
3438    type Output = Self;
3439    for_each_int_type!(unchecked_int_op, [bitor, |]);
3440}
3441impl std::ops::BitXor for IntValue {
3442    type Output = Self;
3443    for_each_int_type!(unchecked_int_op, [bitxor, ^]);
3444}