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