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