src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs RUST 3,333 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,333.
1//! This module provides a MIR interpreter, which is used in const eval.23use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range};45use base_db::{Crate, target::TargetLoadError};6use either::Either;7use hir_def::{8    AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId,9    VariantId,10    expr_store::{Body, ExpressionStore, HygieneId},11    item_tree::FieldsShape,12    lang_item::LangItems,13    layout::{TagEncoding, Variants},14    resolver::{HasResolver, ValueNs},15    signatures::{16        EnumSignature, FunctionSignature, StaticFlags, StaticSignature, StructFlags,17        StructSignature, TraitSignature,18    },19};20use hir_expand::{InFile, mod_path::path};21use la_arena::ArenaMap;22use macros::GenericTypeVisitable;23use rustc_abi::{Size, TargetDataLayout};24use rustc_apfloat::{25    Float,26    ieee::{Half as f16, Quad as f128},27};28use rustc_ast_ir::Mutability;29use rustc_hash::{FxHashMap, FxHashSet};30use rustc_type_ir::{31    AliasTyKind,32    inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},33};34use span::FileId;35use stdx::never;36use syntax::{SyntaxNodePtr, TextRange};37use triomphe::Arc;3839use crate::{40    CallableDefId, ComplexMemoryMap, InferBodyId, InferenceResult, MemoryMap, ParamEnvAndCrate,41    consteval::{self, ConstEvalError, try_const_usize},42    db::{GeneralConstId, HirDatabase, InternedClosureId},43    display::{ClosureStyle, DisplayTarget, HirDisplay},44    infer::PointerCast,45    layout::{Layout, LayoutError, RustcEnumVariantIdx},46    method_resolution::{is_dyn_method, lookup_impl_const},47    next_solver::{48        AliasTy, Allocation, AllocationData, Const, ConstKind, DbInterner, ErrorGuaranteed,49        GenericArgs, Region, StoredTy, Ty, TyKind, TypingMode, UnevaluatedConst, ValTree,50        infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},51        obligation_ctxt::ObligationCtxt,52    },53    traits::FnTrait,54    utils::detect_variant_from_bytes,55};5657use super::{58    AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan,59    Operand, OperandKind, Place, PlaceElem, PlaceRef, PlaceTy, ProjectionElem, Rvalue,60    StatementKind, TerminatorKind, UnOp, return_slot,61};6263mod shim;64#[cfg(test)]65mod tests;6667macro_rules! from_bytes {68    ($ty:tt, $value:expr) => {69        ($ty::from_le_bytes(match ($value).try_into() {70            Ok(it) => it,71            Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $ty).into())),72        }))73    };74    ($apfloat:tt, $bits:tt, $value:expr) => {75        // FIXME(#17451): Switch to builtin `f16` and `f128` once they are stable.76        $apfloat::from_bits($bits::from_le_bytes(match ($value).try_into() {77            Ok(it) => it,78            Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $apfloat).into())),79        }).into())80    };81}82use from_bytes;8384macro_rules! not_supported {85    ($it: expr) => {86        return Err($crate::mir::eval::MirEvalError::NotSupported(format!($it)))87    };88}89use not_supported;9091#[derive(Debug, Default, Clone, PartialEq, Eq, GenericTypeVisitable)]92pub struct VTableMap<'db> {93    ty_to_id: FxHashMap<Ty<'db>, usize>,94    id_to_ty: Vec<Ty<'db>>,95}9697impl<'db> VTableMap<'db> {98    const OFFSET: usize = 1000; // We should add some offset to ids to make 0 (null) an invalid id.99100    fn id(&mut self, ty: Ty<'db>) -> usize {101        if let Some(it) = self.ty_to_id.get(&ty) {102            return *it;103        }104        let id = self.id_to_ty.len() + VTableMap::OFFSET;105        self.id_to_ty.push(ty);106        self.ty_to_id.insert(ty, id);107        id108    }109110    pub(crate) fn ty(&self, id: usize) -> Result<'db, Ty<'db>> {111        id.checked_sub(VTableMap::OFFSET)112            .and_then(|id| self.id_to_ty.get(id).copied())113            .ok_or(MirEvalError::InvalidVTableId(id))114    }115116    fn ty_of_bytes(&self, bytes: &[u8]) -> Result<'db, Ty<'db>> {117        let id = from_bytes!(usize, bytes);118        self.ty(id)119    }120121    pub fn shrink_to_fit(&mut self) {122        self.id_to_ty.shrink_to_fit();123        self.ty_to_id.shrink_to_fit();124    }125126    fn is_empty(&self) -> bool {127        self.id_to_ty.is_empty() && self.ty_to_id.is_empty()128    }129}130131#[derive(Debug, Default, Clone, PartialEq, Eq)]132struct TlsData {133    keys: Vec<u128>,134}135136impl TlsData {137    fn create_key(&mut self) -> usize {138        self.keys.push(0);139        self.keys.len() - 1140    }141142    fn get_key(&mut self, key: usize) -> Result<'static, u128> {143        let r = self.keys.get(key).ok_or_else(|| {144            MirEvalError::UndefinedBehavior(format!("Getting invalid tls key {key}"))145        })?;146        Ok(*r)147    }148149    fn set_key(&mut self, key: usize, value: u128) -> Result<'static, ()> {150        let r = self.keys.get_mut(key).ok_or_else(|| {151            MirEvalError::UndefinedBehavior(format!("Setting invalid tls key {key}"))152        })?;153        *r = value;154        Ok(())155    }156}157158struct StackFrame<'a> {159    locals: Locals<'a>,160    destination: Option<BasicBlockId>,161    prev_stack_ptr: usize,162    span: (MirSpan, InferBodyId),163}164165#[derive(Clone)]166enum MirOrDynIndex<'a> {167    Mir(&'a MirBody),168    Dyn(usize),169}170171pub struct Evaluator<'a, 'db> {172    db: &'db dyn HirDatabase,173    param_env: ParamEnvAndCrate<'db>,174    target_data_layout: &'db TargetDataLayout,175    stack: Vec<u8>,176    heap: Vec<u8>,177    code_stack: Vec<StackFrame<'a>>,178    /// Stores the global location of the statics. We const evaluate every static first time we need it179    /// and see it's missing, then we add it to this to reuse.180    static_locations: FxHashMap<StaticId, Address>,181    /// We don't really have function pointers, i.e. pointers to some assembly instructions that we can run. Instead, we182    /// store the type as an interned id in place of function and vtable pointers, and we recover back the type at the183    /// time of use.184    vtable_map: VTableMap<'db>,185    thread_local_storage: TlsData,186    random_state: oorandom::Rand64,187    stdout: Vec<u8>,188    stderr: Vec<u8>,189    layout_cache: RefCell<FxHashMap<Ty<'db>, Arc<Layout>>>,190    projected_ty_cache: RefCell<FxHashMap<(PlaceTy<'db>, PlaceElem), PlaceTy<'db>>>,191    not_special_fn_cache: RefCell<FxHashSet<FunctionId>>,192    mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, GenericArgs<'db>), MirOrDynIndex<'a>>>,193    /// Constantly dropping and creating `Locals` is very costly. We store194    /// old locals that we normally want to drop here, to reuse their allocations195    /// later.196    unused_locals_store: RefCell<FxHashMap<InferBodyId, Vec<Locals<'a>>>>,197    cached_ptr_size: usize,198    cached_fn_trait_func: Option<FunctionId>,199    cached_fn_mut_trait_func: Option<FunctionId>,200    cached_fn_once_trait_func: Option<FunctionId>,201    crate_id: Crate,202    // FIXME: This is a workaround, see the comment on `interpret_mir`203    assert_placeholder_ty_is_unused: bool,204    /// A general limit on execution, to prevent non terminating programs from breaking r-a main process205    execution_limit: usize,206    /// An additional limit on stack depth, to prevent stack overflow207    stack_depth_limit: usize,208    /// Maximum count of bytes that heap and stack can grow209    memory_limit: usize,210    infcx: InferCtxt<'db>,211}212213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]214enum Address {215    Stack(usize),216    Heap(usize),217    Invalid(usize),218}219220use Address::*;221222#[derive(Debug, Clone, Copy)]223struct Interval {224    addr: Address,225    size: usize,226}227228#[derive(Debug, Clone)]229struct IntervalAndTy<'db> {230    interval: Interval,231    ty: Ty<'db>,232}233234impl Interval {235    fn new(addr: Address, size: usize) -> Self {236        Self { addr, size }237    }238239    fn get<'b, 'a, 'db: 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {240        memory.read_memory(self.addr, self.size)241    }242243    fn write_from_bytes<'a, 'db: 'a>(244        &self,245        memory: &mut Evaluator<'a, 'db>,246        bytes: &[u8],247    ) -> Result<'db, ()> {248        memory.write_memory(self.addr, bytes)249    }250251    fn write_from_interval<'a, 'db: 'a>(252        &self,253        memory: &mut Evaluator<'a, 'db>,254        interval: Interval,255    ) -> Result<'db, ()> {256        memory.copy_from_interval(self.addr, interval)257    }258259    fn slice(self, range: Range<usize>) -> Interval {260        Interval { addr: self.addr.offset(range.start), size: range.len() }261    }262}263264impl<'db> IntervalAndTy<'db> {265    fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]>266    where267        'db: 'a,268    {269        memory.read_memory(self.interval.addr, self.interval.size)270    }271272    fn new<'a>(273        addr: Address,274        ty: Ty<'db>,275        evaluator: &Evaluator<'a, 'db>,276        locals: &Locals<'a>,277    ) -> Result<'db, IntervalAndTy<'db>>278    where279        'db: 'a,280    {281        let size = evaluator.size_of_sized(ty, locals, "type of interval")?;282        Ok(IntervalAndTy { interval: Interval { addr, size }, ty })283    }284}285286enum IntervalOrOwned {287    Owned(Vec<u8>),288    Borrowed(Interval),289}290291impl From<Interval> for IntervalOrOwned {292    fn from(it: Interval) -> IntervalOrOwned {293        IntervalOrOwned::Borrowed(it)294    }295}296297impl IntervalOrOwned {298    fn get<'b, 'a, 'db: 'a>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {299        Ok(match self {300            IntervalOrOwned::Owned(o) => o,301            IntervalOrOwned::Borrowed(b) => b.get(memory)?,302        })303    }304}305306#[cfg(target_pointer_width = "64")]307const STACK_OFFSET: usize = 1 << 60;308#[cfg(target_pointer_width = "64")]309const HEAP_OFFSET: usize = 1 << 59;310311#[cfg(target_pointer_width = "32")]312const STACK_OFFSET: usize = 1 << 30;313#[cfg(target_pointer_width = "32")]314const HEAP_OFFSET: usize = 1 << 29;315316impl Address {317    #[allow(clippy::double_parens)]318    fn from_bytes<'db>(it: &[u8]) -> Result<'db, Self> {319        Ok(Address::from_usize(from_bytes!(usize, it)))320    }321322    fn from_usize(it: usize) -> Self {323        if it > STACK_OFFSET {324            Stack(it - STACK_OFFSET)325        } else if it > HEAP_OFFSET {326            Heap(it - HEAP_OFFSET)327        } else {328            Invalid(it)329        }330    }331332    fn to_bytes(&self) -> [u8; size_of::<usize>()] {333        usize::to_le_bytes(self.to_usize())334    }335336    fn to_usize(&self) -> usize {337        match self {338            Stack(it) => *it + STACK_OFFSET,339            Heap(it) => *it + HEAP_OFFSET,340            Invalid(it) => *it,341        }342    }343344    fn map(&self, f: impl FnOnce(usize) -> usize) -> Address {345        match self {346            Stack(it) => Stack(f(*it)),347            Heap(it) => Heap(f(*it)),348            Invalid(it) => Invalid(f(*it)),349        }350    }351352    fn offset(&self, offset: usize) -> Address {353        self.map(|it| it + offset)354    }355}356357#[derive(Clone, PartialEq, Eq)]358pub enum MirEvalError {359    ConstEvalError(String, Box<ConstEvalError>),360    LayoutError(LayoutError, StoredTy),361    TargetDataLayoutNotAvailable(TargetLoadError),362    /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected363    /// then use this type of error.364    UndefinedBehavior(String),365    Panic(String),366    // FIXME: This should be folded into ConstEvalError?367    MirLowerError(FunctionId, MirLowerError),368    MirLowerErrorForClosure(InternedClosureId, MirLowerError),369    TypeIsUnsized(StoredTy, &'static str),370    NotSupported(String),371    InvalidConst,372    InFunction(373        Box<MirEvalError>,374        Vec<(Either<FunctionId, InternedClosureId>, MirSpan, InferBodyId)>,375    ),376    ExecutionLimitExceeded,377    StackOverflow,378    /// FIXME: Fold this into InternalError379    InvalidVTableId(usize),380    /// ?381    CoerceUnsizedError(StoredTy),382    /// These should not occur, usually indicates a bug in mir lowering.383    InternalError(Box<str>),384}385386impl MirEvalError {387    pub fn pretty_print(388        &self,389        f: &mut String,390        db: &dyn HirDatabase,391        span_formatter: impl Fn(FileId, TextRange) -> String,392        display_target: DisplayTarget,393    ) -> std::result::Result<(), std::fmt::Error> {394        writeln!(f, "Mir eval error:")?;395        let mut err = self;396        while let MirEvalError::InFunction(e, stack) = err {397            err = e;398            for (func, span, def) in stack.iter().take(30).rev() {399                match func {400                    Either::Left(func) => {401                        let function_name = FunctionSignature::of(db, *func);402                        writeln!(403                            f,404                            "In function {} ({:?})",405                            function_name.name.display(db, display_target.edition),406                            func407                        )?;408                    }409                    Either::Right(closure) => {410                        writeln!(f, "In {closure:?}")?;411                    }412                }413                let (source_map, self_param_syntax) = match *def {414                    InferBodyId::DefWithBodyId(def) => {415                        let body = &Body::with_source_map(db, def).1;416                        (&**body, body.self_param_syntax())417                    }418                    InferBodyId::AnonConstId(def) => {419                        let store = ExpressionStore::with_source_map(db, def.loc(db).owner).1;420                        (store, None)421                    }422                };423                let span: InFile<SyntaxNodePtr> = match span {424                    MirSpan::ExprId(e) => match source_map.expr_syntax(*e) {425                        Ok(s) => s.map(|it| it.into()),426                        Err(_) => continue,427                    },428                    MirSpan::PatId(p) => match source_map.pat_syntax(*p) {429                        Ok(s) => s.map(|it| it.syntax_node_ptr()),430                        Err(_) => continue,431                    },432                    MirSpan::BindingId(b) => {433                        match source_map434                            .patterns_for_binding(*b)435                            .iter()436                            .find_map(|p| source_map.pat_syntax(*p).ok())437                        {438                            Some(s) => s.map(|it| it.syntax_node_ptr()),439                            None => continue,440                        }441                    }442                    MirSpan::SelfParam => match self_param_syntax {443                        Some(s) => s.map(|it| it.syntax_node_ptr()),444                        None => continue,445                    },446                    MirSpan::Unknown => continue,447                };448                let file_id = span.file_id.original_file(db);449                let text_range = span.value.text_range();450                writeln!(f, "{}", span_formatter(file_id.file_id(db), text_range))?;451            }452        }453        match err {454            MirEvalError::InFunction(..) => unreachable!(),455            MirEvalError::LayoutError(err, ty) => {456                write!(457                    f,458                    "Layout for type `{}` is not available due {err:?}",459                    ty.as_ref()460                        .display(db, display_target)461                        .with_closure_style(ClosureStyle::ClosureWithId)462                )?;463            }464            MirEvalError::MirLowerError(func, err) => {465                let function_name = FunctionSignature::of(db, *func);466                let self_ = match func.lookup(db).container {467                    ItemContainerId::ImplId(impl_id) => Some({468                        db.impl_self_ty(impl_id)469                            .instantiate_identity()470                            .skip_norm_wip()471                            .display(db, display_target)472                            .to_string()473                    }),474                    ItemContainerId::TraitId(it) => Some(475                        TraitSignature::of(db, it)476                            .name477                            .display(db, display_target.edition)478                            .to_string(),479                    ),480                    _ => None,481                };482                writeln!(483                    f,484                    "MIR lowering for function `{}{}{}` ({:?}) failed due:",485                    self_.as_deref().unwrap_or_default(),486                    if self_.is_some() { "::" } else { "" },487                    function_name.name.display(db, display_target.edition),488                    func489                )?;490                err.pretty_print(f, db, span_formatter, display_target)?;491            }492            MirEvalError::ConstEvalError(name, err) => {493                MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(494                    f,495                    db,496                    span_formatter,497                    display_target,498                )?;499            }500            MirEvalError::UndefinedBehavior(_)501            | MirEvalError::TargetDataLayoutNotAvailable(_)502            | MirEvalError::Panic(_)503            | MirEvalError::MirLowerErrorForClosure(_, _)504            | MirEvalError::TypeIsUnsized(_, _)505            | MirEvalError::NotSupported(_)506            | MirEvalError::InvalidConst507            | MirEvalError::ExecutionLimitExceeded508            | MirEvalError::StackOverflow509            | MirEvalError::CoerceUnsizedError(_)510            | MirEvalError::InternalError(_)511            | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?,512        }513        Ok(())514    }515516    pub fn is_panic(&self) -> Option<&str> {517        let mut err = self;518        while let MirEvalError::InFunction(e, _) = err {519            err = e;520        }521        match err {522            MirEvalError::Panic(msg) => Some(msg),523            _ => None,524        }525    }526}527528impl std::fmt::Debug for MirEvalError {529    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {530        match self {531            Self::ConstEvalError(arg0, arg1) => {532                f.debug_tuple("ConstEvalError").field(arg0).field(arg1).finish()533            }534            Self::LayoutError(arg0, arg1) => {535                f.debug_tuple("LayoutError").field(arg0).field(arg1).finish()536            }537            Self::UndefinedBehavior(arg0) => {538                f.debug_tuple("UndefinedBehavior").field(arg0).finish()539            }540            Self::Panic(msg) => write!(f, "Panic with message:\n{msg:?}"),541            Self::TargetDataLayoutNotAvailable(arg0) => {542                f.debug_tuple("TargetDataLayoutNotAvailable").field(arg0).finish()543            }544            Self::TypeIsUnsized(ty, it) => write!(f, "{ty:?} is unsized. {it} should be sized."),545            Self::ExecutionLimitExceeded => write!(f, "execution limit exceeded"),546            Self::StackOverflow => write!(f, "stack overflow"),547            Self::MirLowerError(arg0, arg1) => {548                f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish()549            }550            Self::MirLowerErrorForClosure(arg0, arg1) => {551                f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish()552            }553            Self::CoerceUnsizedError(arg0) => {554                f.debug_tuple("CoerceUnsizedError").field(arg0).finish()555            }556            Self::InternalError(arg0) => f.debug_tuple("InternalError").field(arg0).finish(),557            Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),558            Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),559            Self::InvalidConst => f.write_str("InvalidConst"),560            Self::InFunction(e, stack) => {561                f.debug_struct("WithStack").field("error", e).field("stack", &stack).finish()562            }563        }564    }565}566567type Result<'db, T> = std::result::Result<T, MirEvalError>;568569#[derive(Debug, Default)]570struct DropFlags<'db> {571    need_drop: FxHashSet<PlaceRef<'db>>,572}573574impl<'db> DropFlags<'db> {575    fn add_place(&mut self, p: PlaceRef<'db>) {576        if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) {577            return;578        }579        self.need_drop.retain(|it| !p.is_parent(*it));580        self.need_drop.insert(p);581    }582583    fn remove_place(&mut self, p: PlaceRef<'db>) -> bool {584        // FIXME: replace parents with parts585        if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(it)) {586            self.need_drop.remove(&parent);587            return true;588        }589        self.need_drop.remove(&p)590    }591592    fn clear(&mut self) {593        self.need_drop.clear();594    }595}596597#[derive(Debug)]598struct Locals<'a> {599    ptr: ArenaMap<LocalId, Interval>,600    body: &'a MirBody,601    drop_flags: DropFlags<'a>,602}603604pub struct MirOutput {605    stdout: Vec<u8>,606    stderr: Vec<u8>,607}608609impl MirOutput {610    pub fn stdout(&self) -> Cow<'_, str> {611        String::from_utf8_lossy(&self.stdout)612    }613    pub fn stderr(&self) -> Cow<'_, str> {614        String::from_utf8_lossy(&self.stderr)615    }616}617618pub fn interpret_mir<'a, 'db: 'a>(619    db: &'db dyn HirDatabase,620    body: &MirBody,621    // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now622    // they share their body with their parent, so in MIR lowering we have locals of the parent body, which623    // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has624    // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can625    // (and probably should) do better here, for example by excluding bindings outside of the target expression.626    assert_placeholder_ty_is_unused: bool,627    trait_env: Option<ParamEnvAndCrate<'db>>,628) -> Result<'db, (Result<'db, Allocation<'db>>, MirOutput)> {629    let ty = body.locals[return_slot()].ty.as_ref();630    let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;631    let it: Result<'db, Allocation<'db>> = (|| {632        if evaluator.ptr_size() != size_of::<usize>() {633            not_supported!("targets with different pointer size from host");634        }635        let interval = evaluator.interpret_mir(body, None.into_iter())?;636        let bytes = interval.get(&evaluator)?;637        let mut memory_map = evaluator.create_memory_map(638            bytes,639            ty,640            &Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },641        )?;642        let bytes = Box::from(bytes);643        let memory_map = if memory_map.memory.is_empty() && evaluator.vtable_map.is_empty() {644            MemoryMap::Empty645        } else {646            memory_map.vtable = mem::take(&mut evaluator.vtable_map);647            memory_map.vtable.shrink_to_fit();648            MemoryMap::Complex(Box::new(memory_map))649        };650        Ok(Allocation::new(AllocationData { ty, memory: bytes, memory_map }))651    })();652    Ok((it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr }))653}654655#[cfg(test)]656const EXECUTION_LIMIT: usize = 100_000;657#[cfg(not(test))]658const EXECUTION_LIMIT: usize = 10_000_000;659660impl<'a, 'db: 'a> Evaluator<'a, 'db> {661    pub fn new(662        db: &'db dyn HirDatabase,663        owner: InferBodyId,664        assert_placeholder_ty_is_unused: bool,665        trait_env: Option<ParamEnvAndCrate<'db>>,666    ) -> Result<'db, Evaluator<'a, 'db>> {667        let module = owner.module(db);668        let crate_id = module.krate(db);669        let target_data_layout = match db.target_data_layout(crate_id) {670            Ok(target_data_layout) => target_data_layout,671            Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)),672        };673        let cached_ptr_size = target_data_layout.pointer_size().bytes_usize();674        let interner = DbInterner::new_with(db, crate_id);675        let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);676        let lang_items = interner.lang_items();677        Ok(Evaluator {678            target_data_layout,679            stack: vec![0],680            heap: vec![0],681            code_stack: vec![],682            vtable_map: VTableMap::default(),683            thread_local_storage: TlsData::default(),684            static_locations: Default::default(),685            db,686            random_state: oorandom::Rand64::new(0),687            param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate {688                param_env: db.trait_environment(owner.generic_def(db)),689                krate: crate_id,690            }),691            crate_id,692            stdout: vec![],693            stderr: vec![],694            assert_placeholder_ty_is_unused,695            stack_depth_limit: 100,696            execution_limit: EXECUTION_LIMIT,697            memory_limit: 1_000_000_000, // 2GB, 1GB for stack and 1GB for heap698            layout_cache: RefCell::new(Default::default()),699            projected_ty_cache: RefCell::new(Default::default()),700            not_special_fn_cache: RefCell::new(Default::default()),701            mir_or_dyn_index_cache: RefCell::new(Default::default()),702            unused_locals_store: RefCell::new(Default::default()),703            cached_ptr_size,704            cached_fn_trait_func: lang_items.Fn_call,705            cached_fn_mut_trait_func: lang_items.FnMut_call_mut,706            cached_fn_once_trait_func: lang_items.FnOnce_call_once,707            infcx,708        })709    }710711    #[inline]712    fn interner(&self) -> DbInterner<'db> {713        self.infcx.interner714    }715716    #[inline]717    fn lang_items(&self) -> &'db LangItems {718        self.infcx.interner.lang_items()719    }720721    fn place_addr(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Address> {722        Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0)723    }724725    fn place_interval(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> {726        let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?;727        Ok(Interval {728            addr: place_addr_and_ty.0,729            size: self.size_of_sized(730                place_addr_and_ty.1,731                locals,732                "Type of place that we need its interval",733            )?,734        })735    }736737    fn ptr_size(&self) -> usize {738        self.cached_ptr_size739    }740741    fn projected_ty(&self, ty: PlaceTy<'db>, proj: PlaceElem) -> PlaceTy<'db> {742        let pair = (ty, proj);743        if let Some(r) = self.projected_ty_cache.borrow().get(&pair) {744            return *r;745        }746        let (ty, proj) = pair;747        let r = ty.projection_ty(&self.infcx, &proj, self.param_env.param_env);748        self.projected_ty_cache.borrow_mut().insert((ty, proj), r);749        r750    }751752    fn place_addr_and_ty_and_metadata<'b>(753        &'b self,754        p: &Place,755        locals: &'b Locals<'a>,756    ) -> Result<'db, (Address, Ty<'db>, Option<IntervalOrOwned>)> {757        let mut addr = locals.ptr[p.local].addr;758        let mut ty = PlaceTy::from_ty(locals.body.locals[p.local].ty.as_ref());759        let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized760        for proj in p.projection.lookup() {761            let prev_ty = ty;762            ty = self.projected_ty(ty, *proj);763            match proj {764                ProjectionElem::Deref => {765                    metadata = if self.size_align_of(ty.ty, locals)?.is_none() {766                        Some(767                            Interval { addr: addr.offset(self.ptr_size()), size: self.ptr_size() }768                                .into(),769                        )770                    } else {771                        None772                    };773                    let it = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?);774                    addr = Address::from_usize(it);775                }776                ProjectionElem::Index(op) => {777                    let offset = from_bytes!(778                        usize,779                        self.read_memory(locals.ptr[*op].addr, self.ptr_size())?780                    );781                    metadata = None; // Result of index is always sized782                    let ty_size =783                        self.size_of_sized(ty.ty, locals, "array inner type should be sized")?;784                    addr = addr.offset(ty_size * offset);785                }786                &ProjectionElem::ConstantIndex { from_end, offset } => {787                    let offset = if from_end {788                        let len = match prev_ty.ty.kind() {789                            TyKind::Array(_, c) => match try_const_usize(self.db, c) {790                                Some(it) => it as u64,791                                None => {792                                    not_supported!("indexing array with unknown const from end")793                                }794                            },795                            TyKind::Slice(_) => match metadata {796                                Some(it) => from_bytes!(u64, it.get(self)?),797                                None => not_supported!("slice place without metadata"),798                            },799                            _ => not_supported!("bad type for const index"),800                        };801                        (len - offset - 1) as usize802                    } else {803                        offset as usize804                    };805                    metadata = None; // Result of index is always sized806                    let ty_size =807                        self.size_of_sized(ty.ty, locals, "array inner type should be sized")?;808                    addr = addr.offset(ty_size * offset);809                }810                &ProjectionElem::Subslice { from, to } => {811                    let inner_ty = match ty.ty.kind() {812                        TyKind::Array(inner, _) | TyKind::Slice(inner) => inner,813                        _ => Ty::new_error(self.interner(), ErrorGuaranteed),814                    };815                    metadata = match metadata {816                        Some(it) => {817                            let prev_len = from_bytes!(u64, it.get(self)?);818                            Some(IntervalOrOwned::Owned(819                                (prev_len - from - to).to_le_bytes().to_vec(),820                            ))821                        }822                        None => None,823                    };824                    let ty_size =825                        self.size_of_sized(inner_ty, locals, "array inner type should be sized")?;826                    addr = addr.offset(ty_size * (from as usize));827                }828                ProjectionElem::Field(f) => {829                    let layout = self.layout(prev_ty.ty)?;830                    let variant_layout = match &layout.variants {831                        Variants::Single { .. } | Variants::Empty => &layout,832                        Variants::Multiple { variants, .. } => {833                            &variants[match prev_ty.variant_id {834                                Some(hir_def::VariantId::EnumVariantId(it)) => {835                                    RustcEnumVariantIdx(it.index(self.db))836                                }837                                _ => {838                                    return Err(MirEvalError::InternalError(839                                        "mismatched layout".into(),840                                    ));841                                }842                            }]843                        }844                    };845                    let offset = variant_layout.fields.offset(f.0 as usize).bytes_usize();846                    addr = addr.offset(offset);847                    // Unsized field metadata is equal to the metadata of the struct848                    if self.size_align_of(ty.ty, locals)?.is_some() {849                        metadata = None;850                    }851                }852                ProjectionElem::Downcast(_) => {853                    // no runtime effect854                }855            }856        }857        Ok((addr, ty.ty, metadata))858    }859860    fn layout(&self, ty: Ty<'db>) -> Result<'db, Arc<Layout>> {861        if let Some(x) = self.layout_cache.borrow().get(&ty) {862            return Ok(x.clone());863        }864        let r = self865            .db866            .layout_of_ty(ty.store(), self.param_env.store())867            .map_err(|e| MirEvalError::LayoutError(e, ty.store()))?;868        self.layout_cache.borrow_mut().insert(ty, r.clone());869        Ok(r)870    }871872    fn layout_adt(&self, adt: AdtId, subst: GenericArgs<'db>) -> Result<'db, Arc<Layout>> {873        self.layout(Ty::new_adt(self.interner(), adt, subst))874    }875876    fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a>) -> Result<'db, Ty<'db>> {877        Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1)878    }879880    fn operand_ty(&self, o: &Operand, locals: &Locals<'a>) -> Result<'db, Ty<'db>> {881        Ok(match &o.kind {882            OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?,883            OperandKind::Constant { konst: _, ty } => ty.as_ref(),884            OperandKind::Allocation { allocation } => allocation.as_ref().ty,885            &OperandKind::Static(s) => {886                let ty = InferenceResult::of(self.db, DefWithBodyId::from(s))887                    .expr_ty(Body::of(self.db, s.into()).root_expr());888                Ty::new_ref(889                    self.interner(),890                    Region::new_static(self.interner()),891                    ty,892                    Mutability::Not,893                )894            }895        })896    }897898    fn operand_ty_and_eval(899        &mut self,900        o: &Operand,901        locals: &mut Locals<'a>,902    ) -> Result<'db, IntervalAndTy<'db>> {903        Ok(IntervalAndTy {904            interval: self.eval_operand(o, locals)?,905            ty: self.operand_ty(o, locals)?,906        })907    }908909    fn interpret_mir(910        &mut self,911        body: &'a MirBody,912        args: impl Iterator<Item = IntervalOrOwned>,913    ) -> Result<'db, Interval> {914        if let Some(it) = self.stack_depth_limit.checked_sub(1) {915            self.stack_depth_limit = it;916        } else {917            return Err(MirEvalError::StackOverflow);918        }919        let mut current_block_idx = body.start_block;920        let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body, None)?;921        self.fill_locals_for_body(body, &mut locals, args)?;922        let prev_code_stack = mem::take(&mut self.code_stack);923        let span = (MirSpan::Unknown, body.owner);924        self.code_stack.push(StackFrame { locals, destination: None, prev_stack_ptr, span });925        'stack: loop {926            let Some(mut my_stack_frame) = self.code_stack.pop() else {927                not_supported!("missing stack frame");928            };929            let e = (|| {930                let locals = &mut my_stack_frame.locals;931                let body = locals.body.clone();932                loop {933                    let current_block = &body.basic_blocks[current_block_idx];934                    if let Some(it) = self.execution_limit.checked_sub(1) {935                        self.execution_limit = it;936                    } else {937                        return Err(MirEvalError::ExecutionLimitExceeded);938                    }939                    for statement in &current_block.statements {940                        match &statement.kind {941                            StatementKind::Assign(l, r) => {942                                let addr = self.place_addr(l, locals)?;943                                let result = self.eval_rvalue(r, locals)?;944                                self.copy_from_interval_or_owned(addr, result)?;945                                locals.drop_flags.add_place(l.as_ref());946                            }947                            StatementKind::Deinit(_) => not_supported!("de-init statement"),948                            StatementKind::StorageLive(_)949                            | StatementKind::FakeRead(_)950                            | StatementKind::StorageDead(_)951                            | StatementKind::Nop => (),952                        }953                    }954                    let Some(terminator) = current_block.terminator.as_ref() else {955                        not_supported!("block without terminator");956                    };957                    match &terminator.kind {958                        TerminatorKind::Goto { target } => {959                            current_block_idx = *target;960                        }961                        TerminatorKind::Call {962                            func,963                            args,964                            destination,965                            target,966                            cleanup: _,967                            from_hir_call: _,968                        } => {969                            let destination_interval = self.place_interval(destination, locals)?;970                            let fn_ty = self.operand_ty(func, locals)?;971                            let args = args972                                .iter()973                                .map(|it| self.operand_ty_and_eval(it, locals))974                                .collect::<Result<'db, Vec<_>>>()?;975                            let stack_frame = match fn_ty.kind() {976                                TyKind::FnPtr(..) => {977                                    let bytes = self.eval_operand(func, locals)?;978                                    self.exec_fn_pointer(979                                        bytes,980                                        destination_interval,981                                        &args,982                                        locals,983                                        *target,984                                        terminator.span,985                                    )?986                                }987                                TyKind::FnDef(def, generic_args) => self.exec_fn_def(988                                    def.0,989                                    generic_args,990                                    destination_interval,991                                    &args,992                                    locals,993                                    *target,994                                    terminator.span,995                                )?,996                                it => not_supported!("unknown function type {it:?}"),997                            };998                            locals.drop_flags.add_place(destination.as_ref());999                            if let Some(stack_frame) = stack_frame {1000                                self.code_stack.push(my_stack_frame);1001                                current_block_idx = stack_frame.locals.body.start_block;1002                                self.code_stack.push(stack_frame);1003                                return Ok(None);1004                            } else {1005                                current_block_idx =1006                                    target.ok_or(MirEvalError::UndefinedBehavior(1007                                        "Diverging function returned".to_owned(),1008                                    ))?;1009                            }1010                        }1011                        TerminatorKind::SwitchInt { discr, targets } => {1012                            let val = u128::from_le_bytes(pad16(1013                                self.eval_operand(discr, locals)?.get(self)?,1014                                false,1015                            ));1016                            current_block_idx = targets.target_for_value(val);1017                        }1018                        TerminatorKind::Return => {1019                            break;1020                        }1021                        TerminatorKind::Unreachable => {1022                            return Err(MirEvalError::UndefinedBehavior(1023                                "unreachable executed".to_owned(),1024                            ));1025                        }1026                        TerminatorKind::Drop { place, target, unwind: _ } => {1027                            self.drop_place(place, locals, terminator.span)?;1028                            current_block_idx = *target;1029                        }1030                        _ => not_supported!("unknown terminator"),1031                    }1032                }1033                Ok(Some(my_stack_frame))1034            })();1035            let my_stack_frame = match e {1036                Ok(None) => continue 'stack,1037                Ok(Some(x)) => x,1038                Err(e) => {1039                    let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack);1040                    let mut error_stack = vec![];1041                    for frame in my_code_stack.into_iter().rev() {1042                        if let Some(f) = frame.locals.body.owner.as_function() {1043                            error_stack.push((Either::Left(f), frame.span.0, frame.span.1));1044                        }1045                    }1046                    return Err(MirEvalError::InFunction(Box::new(e), error_stack));1047                }1048            };1049            let return_interval = my_stack_frame.locals.ptr[return_slot()];1050            self.unused_locals_store1051                .borrow_mut()1052                .entry(my_stack_frame.locals.body.owner)1053                .or_default()1054                .push(my_stack_frame.locals);1055            match my_stack_frame.destination {1056                None => {1057                    self.code_stack = prev_code_stack;1058                    self.stack_depth_limit += 1;1059                    return Ok(return_interval);1060                }1061                Some(bb) => {1062                    // We don't support const promotion, so we can't truncate the stack yet.1063                    let _ = my_stack_frame.prev_stack_ptr;1064                    // self.stack.truncate(my_stack_frame.prev_stack_ptr);1065                    current_block_idx = bb;1066                }1067            }1068        }1069    }10701071    fn fill_locals_for_body(1072        &mut self,1073        body: &MirBody,1074        locals: &mut Locals<'a>,1075        args: impl Iterator<Item = IntervalOrOwned>,1076    ) -> Result<'db, ()> {1077        let mut remain_args = body.param_locals.len();1078        for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {1079            locals.drop_flags.add_place(l.into());1080            match value {1081                IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,1082                IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,1083            }1084            if remain_args == 0 {1085                return Err(MirEvalError::InternalError("too many arguments".into()));1086            }1087            remain_args -= 1;1088        }1089        if remain_args > 0 {1090            return Err(MirEvalError::InternalError("too few arguments".into()));1091        }1092        Ok(())1093    }10941095    fn create_locals_for_body(1096        &mut self,1097        body: &'a MirBody,1098        destination: Option<Interval>,1099    ) -> Result<'db, (Locals<'a>, usize)> {1100        let mut locals =1101            match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() {1102                None => Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },1103                Some(mut l) => {1104                    l.drop_flags.clear();1105                    l.body = body;1106                    l1107                }1108            };1109        let stack_size = {1110            let mut stack_ptr = self.stack.len();1111            for (id, it) in body.locals.iter() {1112                if id == return_slot()1113                    && let Some(destination) = destination1114                {1115                    locals.ptr.insert(id, destination);1116                    continue;1117                }1118                let (size, align) = self.size_align_of_sized(1119                    it.ty.as_ref(),1120                    &locals,1121                    "no unsized local in extending stack",1122                )?;1123                while !stack_ptr.is_multiple_of(align) {1124                    stack_ptr += 1;1125                }1126                let my_ptr = stack_ptr;1127                stack_ptr += size;1128                locals.ptr.insert(id, Interval { addr: Stack(my_ptr), size });1129            }1130            stack_ptr - self.stack.len()1131        };1132        let prev_stack_pointer = self.stack.len();1133        if stack_size > self.memory_limit {1134            return Err(MirEvalError::Panic(format!(1135                "Stack overflow. Tried to grow stack to {stack_size} bytes"1136            )));1137        }1138        self.stack.extend(std::iter::repeat_n(0, stack_size));1139        Ok((locals, prev_stack_pointer))1140    }11411142    fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'a>) -> Result<'db, IntervalOrOwned> {1143        use IntervalOrOwned::*;1144        Ok(match r {1145            Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?),1146            Rvalue::Ref(_, p) => {1147                let (addr, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?;1148                let mut r = addr.to_bytes().to_vec();1149                if let Some(metadata) = metadata {1150                    r.extend(metadata.get(self)?);1151                }1152                Owned(r)1153            }1154            Rvalue::Len(p) => {1155                let (_, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?;1156                match metadata {1157                    Some(m) => m,1158                    None => {1159                        return Err(MirEvalError::InternalError(1160                            "type without metadata is used for Rvalue::Len".into(),1161                        ));1162                    }1163                }1164            }1165            Rvalue::UnaryOp(op, val) => {1166                let mut c = self.eval_operand(val, locals)?.get(self)?;1167                let mut ty = self.operand_ty(val, locals)?;1168                while let TyKind::Ref(_, z, _) = ty.kind() {1169                    ty = z;1170                    let size = self.size_of_sized(ty, locals, "operand of unary op")?;1171                    c = self.read_memory(Address::from_bytes(c)?, size)?;1172                }1173                if let TyKind::Float(f) = ty.kind() {1174                    match f {1175                        rustc_type_ir::FloatTy::F16 => {1176                            let c = -from_bytes!(f16, u16, c);1177                            Owned(u16::try_from(c.to_bits()).unwrap().to_le_bytes().into())1178                        }1179                        rustc_type_ir::FloatTy::F32 => {1180                            let c = -from_bytes!(f32, c);1181                            Owned(c.to_le_bytes().into())1182                        }1183                        rustc_type_ir::FloatTy::F64 => {1184                            let c = -from_bytes!(f64, c);1185                            Owned(c.to_le_bytes().into())1186                        }1187                        rustc_type_ir::FloatTy::F128 => {1188                            let c = -from_bytes!(f128, u128, c);1189                            Owned(c.to_bits().to_le_bytes().into())1190                        }1191                    }1192                } else {1193                    let mut c = c.to_vec();1194                    if matches!(ty.kind(), TyKind::Bool) {1195                        c[0] = 1 - c[0];1196                    } else {1197                        match op {1198                            UnOp::Not => c.iter_mut().for_each(|it| *it = !*it),1199                            UnOp::Neg => {1200                                c.iter_mut().for_each(|it| *it = !*it);1201                                for k in c.iter_mut() {1202                                    let o;1203                                    (*k, o) = k.overflowing_add(1);1204                                    if !o {1205                                        break;1206                                    }1207                                }1208                            }1209                        }1210                    }1211                    Owned(c)1212                }1213            }1214            Rvalue::CheckedBinaryOp(op, lhs, rhs) => 'binary_op: {1215                let lc = self.eval_operand(lhs, locals)?;1216                let rc = self.eval_operand(rhs, locals)?;1217                let mut lc = lc.get(self)?;1218                let mut rc = rc.get(self)?;1219                let mut ty = self.operand_ty(lhs, locals)?;1220                while let TyKind::Ref(_, z, _) = ty.kind() {1221                    ty = z;1222                    let size = if ty.is_str() {1223                        if *op != BinOp::Eq {1224                            never!("Only eq is builtin for `str`");1225                        }1226                        let ls = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]);1227                        let rs = from_bytes!(usize, &rc[self.ptr_size()..self.ptr_size() * 2]);1228                        if ls != rs {1229                            break 'binary_op Owned(vec![0]);1230                        }1231                        lc = &lc[..self.ptr_size()];1232                        rc = &rc[..self.ptr_size()];1233                        lc = self.read_memory(Address::from_bytes(lc)?, ls)?;1234                        rc = self.read_memory(Address::from_bytes(rc)?, ls)?;1235                        break 'binary_op Owned(vec![u8::from(lc == rc)]);1236                    } else {1237                        self.size_of_sized(ty, locals, "operand of binary op")?1238                    };1239                    lc = self.read_memory(Address::from_bytes(lc)?, size)?;1240                    rc = self.read_memory(Address::from_bytes(rc)?, size)?;1241                }1242                if let TyKind::Float(f) = ty.kind() {1243                    match f {1244                        rustc_type_ir::FloatTy::F16 => {1245                            let l = from_bytes!(f16, u16, lc);1246                            let r = from_bytes!(f16, u16, rc);1247                            match op {1248                                BinOp::Ge1249                                | BinOp::Gt1250                                | BinOp::Le1251                                | BinOp::Lt1252                                | BinOp::Eq1253                                | BinOp::Ne => {1254                                    let r = op.run_compare(l, r) as u8;1255                                    Owned(vec![r])1256                                }1257                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1258                                    let r = match op {1259                                        BinOp::Add => l + r,1260                                        BinOp::Sub => l - r,1261                                        BinOp::Mul => l * r,1262                                        BinOp::Div => l / r,1263                                        _ => unreachable!(),1264                                    };1265                                    Owned(1266                                        u16::try_from(r.value.to_bits())1267                                            .unwrap()1268                                            .to_le_bytes()1269                                            .into(),1270                                    )1271                                }1272                                it => not_supported!(1273                                    "invalid binop {it:?} on floating point operators"1274                                ),1275                            }1276                        }1277                        rustc_type_ir::FloatTy::F32 => {1278                            let l = from_bytes!(f32, lc);1279                            let r = from_bytes!(f32, rc);1280                            match op {1281                                BinOp::Ge1282                                | BinOp::Gt1283                                | BinOp::Le1284                                | BinOp::Lt1285                                | BinOp::Eq1286                                | BinOp::Ne => {1287                                    let r = op.run_compare(l, r) as u8;1288                                    Owned(vec![r])1289                                }1290                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1291                                    let r = match op {1292                                        BinOp::Add => l + r,1293                                        BinOp::Sub => l - r,1294                                        BinOp::Mul => l * r,1295                                        BinOp::Div => l / r,1296                                        _ => unreachable!(),1297                                    };1298                                    Owned(r.to_le_bytes().into())1299                                }1300                                it => not_supported!(1301                                    "invalid binop {it:?} on floating point operators"1302                                ),1303                            }1304                        }1305                        rustc_type_ir::FloatTy::F64 => {1306                            let l = from_bytes!(f64, lc);1307                            let r = from_bytes!(f64, rc);1308                            match op {1309                                BinOp::Ge1310                                | BinOp::Gt1311                                | BinOp::Le1312                                | BinOp::Lt1313                                | BinOp::Eq1314                                | BinOp::Ne => {1315                                    let r = op.run_compare(l, r) as u8;1316                                    Owned(vec![r])1317                                }1318                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1319                                    let r = match op {1320                                        BinOp::Add => l + r,1321                                        BinOp::Sub => l - r,1322                                        BinOp::Mul => l * r,1323                                        BinOp::Div => l / r,1324                                        _ => unreachable!(),1325                                    };1326                                    Owned(r.to_le_bytes().into())1327                                }1328                                it => not_supported!(1329                                    "invalid binop {it:?} on floating point operators"1330                                ),1331                            }1332                        }1333                        rustc_type_ir::FloatTy::F128 => {1334                            let l = from_bytes!(f128, u128, lc);1335                            let r = from_bytes!(f128, u128, rc);1336                            match op {1337                                BinOp::Ge1338                                | BinOp::Gt1339                                | BinOp::Le1340                                | BinOp::Lt1341                                | BinOp::Eq1342                                | BinOp::Ne => {1343                                    let r = op.run_compare(l, r) as u8;1344                                    Owned(vec![r])1345                                }1346                                BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1347                                    let r = match op {1348                                        BinOp::Add => l + r,1349                                        BinOp::Sub => l - r,1350                                        BinOp::Mul => l * r,1351                                        BinOp::Div => l / r,1352                                        _ => unreachable!(),1353                                    };1354                                    Owned(r.value.to_bits().to_le_bytes().into())1355                                }1356                                it => not_supported!(1357                                    "invalid binop {it:?} on floating point operators"1358                                ),1359                            }1360                        }1361                    }1362                } else {1363                    let is_signed = matches!(ty.kind(), TyKind::Int(_));1364                    let l128 = IntValue::from_bytes(lc, is_signed);1365                    let r128 = IntValue::from_bytes(rc, is_signed);1366                    match op {1367                        BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => {1368                            let r = op.run_compare(l128, r128) as u8;1369                            Owned(vec![r])1370                        }1371                        BinOp::BitAnd1372                        | BinOp::BitOr1373                        | BinOp::BitXor1374                        | BinOp::Add1375                        | BinOp::Mul1376                        | BinOp::Div1377                        | BinOp::Rem1378                        | BinOp::Sub => {1379                            let r = match op {1380                                BinOp::Add => l128.checked_add(r128).ok_or_else(|| {1381                                    MirEvalError::Panic(format!("Overflow in {op:?}"))1382                                })?,1383                                BinOp::Mul => l128.checked_mul(r128).ok_or_else(|| {1384                                    MirEvalError::Panic(format!("Overflow in {op:?}"))1385                                })?,1386                                BinOp::Div => l128.checked_div(r128).ok_or_else(|| {1387                                    MirEvalError::Panic(format!("Overflow in {op:?}"))1388                                })?,1389                                BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| {1390                                    MirEvalError::Panic(format!("Overflow in {op:?}"))1391                                })?,1392                                BinOp::Sub => l128.checked_sub(r128).ok_or_else(|| {1393                                    MirEvalError::Panic(format!("Overflow in {op:?}"))1394                                })?,1395                                BinOp::BitAnd => l128 & r128,1396                                BinOp::BitOr => l128 | r128,1397                                BinOp::BitXor => l128 ^ r128,1398                                _ => unreachable!(),1399                            };1400                            Owned(r.to_bytes())1401                        }1402                        BinOp::Shl | BinOp::Shr => {1403                            let r = 'b: {1404                                if let Some(shift_amount) = r128.as_u32() {1405                                    let r = match op {1406                                        BinOp::Shl => l128.checked_shl(shift_amount),1407                                        BinOp::Shr => l128.checked_shr(shift_amount),1408                                        _ => unreachable!(),1409                                    };1410                                    if shift_amount as usize >= lc.len() * 8 {1411                                        return Err(MirEvalError::Panic(format!(1412                                            "Overflow in {op:?}"1413                                        )));1414                                    }1415                                    if let Some(r) = r {1416                                        break 'b r;1417                                    }1418                                };1419                                return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));1420                            };1421                            Owned(r.to_bytes())1422                        }1423                        BinOp::Offset => not_supported!("offset binop"),1424                    }1425                }1426            }1427            Rvalue::Discriminant(p) => {1428                let ty = self.place_ty(p, locals)?;1429                let bytes = self.eval_place(p, locals)?.get(self)?;1430                let result = self.compute_discriminant(ty, bytes)?;1431                Owned(result.to_le_bytes().to_vec())1432            }1433            Rvalue::Repeat(it, len) => {1434                let len = match try_const_usize(self.db, len.as_ref()) {1435                    Some(it) => it as usize,1436                    None => not_supported!("non evaluatable array len in repeat Rvalue"),1437                };1438                let val = self.eval_operand(it, locals)?.get(self)?;1439                let size = len * val.len();1440                Owned(val.iter().copied().cycle().take(size).collect())1441            }1442            Rvalue::ShallowInitBox(_, _) => not_supported!("shallow init box"),1443            Rvalue::ShallowInitBoxWithAlloc(ty) => {1444                let Some((size, align)) = self.size_align_of(ty.as_ref(), locals)? else {1445                    not_supported!("unsized box initialization");1446                };1447                let addr = self.heap_allocate(size, align)?;1448                Owned(addr.to_bytes().to_vec())1449            }1450            Rvalue::CopyForDeref(_) => not_supported!("copy for deref"),1451            Rvalue::Aggregate(kind, values) => {1452                let values = values1453                    .iter()1454                    .map(|it| self.eval_operand(it, locals))1455                    .collect::<Result<'db, Vec<_>>>()?;1456                match kind {1457                    AggregateKind::Array(_) => {1458                        let mut r = vec![];1459                        for it in values {1460                            let value = it.get(self)?;1461                            r.extend(value);1462                        }1463                        Owned(r)1464                    }1465                    AggregateKind::Tuple(ty) => {1466                        let layout = self.layout(ty.as_ref())?;1467                        Owned(self.construct_with_layout(1468                            layout.size.bytes_usize(),1469                            &layout,1470                            None,1471                            values.iter().map(|&it| it.into()),1472                        )?)1473                    }1474                    AggregateKind::Union(it, f) => {1475                        let layout =1476                            self.layout_adt((*it).into(), GenericArgs::empty(self.interner()))?;1477                        let offset = layout1478                            .fields1479                            .offset(u32::from(f.local_id.into_raw()) as usize)1480                            .bytes_usize();1481                        let op = values[0].get(self)?;1482                        let mut result = vec![0; layout.size.bytes_usize()];1483                        result[offset..offset + op.len()].copy_from_slice(op);1484                        Owned(result)1485                    }1486                    AggregateKind::Adt(it, subst) => {1487                        let (size, variant_layout, tag) =1488                            self.layout_of_variant(*it, subst.as_ref(), locals)?;1489                        Owned(self.construct_with_layout(1490                            size,1491                            &variant_layout,1492                            tag,1493                            values.iter().map(|&it| it.into()),1494                        )?)1495                    }1496                    AggregateKind::Closure(ty) => {1497                        let layout = self.layout(ty.as_ref())?;1498                        Owned(self.construct_with_layout(1499                            layout.size.bytes_usize(),1500                            &layout,1501                            None,1502                            values.iter().map(|&it| it.into()),1503                        )?)1504                    }1505                }1506            }1507            Rvalue::Cast(kind, operand, target_ty) => match kind {1508                CastKind::PointerCoercion(cast) => match cast {1509                    PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => {1510                        let current_ty = self.operand_ty(operand, locals)?;1511                        if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) = current_ty.kind() {1512                            let id = self.vtable_map.id(current_ty);1513                            let ptr_size = self.ptr_size();1514                            Owned(id.to_le_bytes()[0..ptr_size].to_vec())1515                        } else {1516                            not_supported!(1517                                "creating a fn pointer from a non FnDef or Closure type"1518                            );1519                        }1520                    }1521                    PointerCast::Unsize => {1522                        let current_ty = self.operand_ty(operand, locals)?;1523                        let addr = self.eval_operand(operand, locals)?;1524                        self.coerce_unsized(addr, current_ty, target_ty.as_ref())?1525                    }1526                    PointerCast::MutToConstPointer | PointerCast::UnsafeFnPointer => {1527                        // This is no-op1528                        Borrowed(self.eval_operand(operand, locals)?)1529                    }1530                    PointerCast::ArrayToPointer => {1531                        // We should remove the metadata part if the current type is slice1532                        Borrowed(self.eval_operand(operand, locals)?.slice(0..self.ptr_size()))1533                    }1534                },1535                CastKind::DynStar => not_supported!("dyn star cast"),1536                CastKind::IntToInt1537                | CastKind::PtrToPtr1538                | CastKind::PointerExposeAddress1539                | CastKind::PointerFromExposedAddress => {1540                    let current_ty = self.operand_ty(operand, locals)?;1541                    let is_signed = matches!(current_ty.kind(), TyKind::Int(_));1542                    let current = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);1543                    let dest_size = self.size_of_sized(1544                        target_ty.as_ref(),1545                        locals,1546                        "destination of int to int cast",1547                    )?;1548                    Owned(current[0..dest_size].to_vec())1549                }1550                CastKind::FloatToInt => {1551                    let ty = self.operand_ty(operand, locals)?;1552                    let TyKind::Float(ty) = ty.kind() else {1553                        not_supported!("invalid float to int cast");1554                    };1555                    let value = self.eval_operand(operand, locals)?.get(self)?;1556                    let value = match ty {1557                        rustc_type_ir::FloatTy::F32 => {1558                            let value = value.try_into().unwrap();1559                            f32::from_le_bytes(value) as f641560                        }1561                        rustc_type_ir::FloatTy::F64 => {1562                            let value = value.try_into().unwrap();1563                            f64::from_le_bytes(value)1564                        }1565                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1566                            not_supported!("unstable floating point type f16 and f128");1567                        }1568                    };1569                    let is_signed = matches!(target_ty.as_ref().kind(), TyKind::Int(_));1570                    let dest_size = self.size_of_sized(1571                        target_ty.as_ref(),1572                        locals,1573                        "destination of float to int cast",1574                    )?;1575                    let dest_bits = dest_size * 8;1576                    let (max, min) = if dest_bits == 128 {1577                        (i128::MAX, i128::MIN)1578                    } else if is_signed {1579                        let max = 1i128 << (dest_bits - 1);1580                        (max - 1, -max)1581                    } else {1582                        ((1i128 << dest_bits) - 1, 0)1583                    };1584                    let value = (value as i128).min(max).max(min);1585                    let result = value.to_le_bytes();1586                    Owned(result[0..dest_size].to_vec())1587                }1588                CastKind::FloatToFloat => {1589                    let ty = self.operand_ty(operand, locals)?;1590                    let TyKind::Float(ty) = ty.kind() else {1591                        not_supported!("invalid float to int cast");1592                    };1593                    let value = self.eval_operand(operand, locals)?.get(self)?;1594                    let value = match ty {1595                        rustc_type_ir::FloatTy::F32 => {1596                            let value = value.try_into().unwrap();1597                            f32::from_le_bytes(value) as f641598                        }1599                        rustc_type_ir::FloatTy::F64 => {1600                            let value = value.try_into().unwrap();1601                            f64::from_le_bytes(value)1602                        }1603                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1604                            not_supported!("unstable floating point type f16 and f128");1605                        }1606                    };1607                    let TyKind::Float(target_ty) = target_ty.as_ref().kind() else {1608                        not_supported!("invalid float to float cast");1609                    };1610                    match target_ty {1611                        rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),1612                        rustc_type_ir::FloatTy::F64 => Owned(value.to_le_bytes().to_vec()),1613                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1614                            not_supported!("unstable floating point type f16 and f128");1615                        }1616                    }1617                }1618                CastKind::IntToFloat => {1619                    let current_ty = self.operand_ty(operand, locals)?;1620                    let is_signed = matches!(current_ty.kind(), TyKind::Int(_));1621                    let value = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);1622                    let value = i128::from_le_bytes(value);1623                    let TyKind::Float(target_ty) = target_ty.as_ref().kind() else {1624                        not_supported!("invalid int to float cast");1625                    };1626                    match target_ty {1627                        rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),1628                        rustc_type_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),1629                        rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1630                            not_supported!("unstable floating point type f16 and f128");1631                        }1632                    }1633                }1634                CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),1635            },1636            Rvalue::ThreadLocalRef(n)1637            | Rvalue::AddressOf(n)1638            | Rvalue::BinaryOp(n)1639            | Rvalue::NullaryOp(n) => match *n {},1640        })1641    }16421643    fn compute_discriminant(&self, ty: Ty<'db>, bytes: &[u8]) -> Result<'db, i128> {1644        let layout = self.layout(ty)?;1645        let TyKind::Adt(adt_def, _) = ty.kind() else {1646            return Ok(0);1647        };1648        let AdtId::EnumId(e) = adt_def.def_id() else {1649            return Ok(0);1650        };1651        match &layout.variants {1652            Variants::Empty => unreachable!(),1653            Variants::Single { index } => {1654                let r =1655                    self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?;1656                Ok(r)1657            }1658            Variants::Multiple { tag, tag_encoding, variants, .. } => {1659                let size = tag.size(self.target_data_layout).bytes_usize();1660                let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field1661                let is_signed = tag.is_signed();1662                match tag_encoding {1663                    TagEncoding::Direct => {1664                        let tag = &bytes[offset..offset + size];1665                        Ok(i128::from_le_bytes(pad16(tag, is_signed)))1666                    }1667                    TagEncoding::Niche { untagged_variant, niche_start, .. } => {1668                        let tag = &bytes[offset..offset + size];1669                        let candidate_tag = i128::from_le_bytes(pad16(tag, is_signed))1670                            .wrapping_sub(*niche_start as i128)1671                            as usize;1672                        let idx = variants1673                            .iter_enumerated()1674                            .map(|(it, _)| it)1675                            .filter(|it| it != untagged_variant)1676                            .nth(candidate_tag)1677                            .unwrap_or(*untagged_variant)1678                            .0;1679                        let result =1680                            self.const_eval_discriminant(e.enum_variants(self.db).variants[idx].0)?;1681                        Ok(result)1682                    }1683                }1684            }1685        }1686    }16871688    fn coerce_unsized_look_through_fields<T>(1689        &self,1690        ty: Ty<'db>,1691        goal: impl Fn(TyKind<'db>) -> Option<T>,1692    ) -> Result<'db, T> {1693        let kind = ty.kind();1694        if let Some(it) = goal(kind) {1695            return Ok(it);1696        }1697        match kind {1698            TyKind::Adt(adt_ef, subst) if let AdtId::StructId(struct_id) = adt_ef.def_id() => {1699                let field_types = self.db.field_types(struct_id.into());1700                if let Some(ty) = field_types1701                    .iter()1702                    .last()1703                    .map(|it| it.1.ty().instantiate(self.interner(), subst))1704                {1705                    return self.coerce_unsized_look_through_fields(ty.skip_norm_wip(), goal);1706                }1707            }1708            TyKind::Pat(ty, _) => return self.coerce_unsized_look_through_fields(ty, goal),1709            _ => (),1710        }1711        Err(MirEvalError::CoerceUnsizedError(ty.store()))1712    }17131714    fn coerce_unsized(1715        &mut self,1716        addr: Interval,1717        current_ty: Ty<'db>,1718        target_ty: Ty<'db>,1719    ) -> Result<'db, IntervalOrOwned> {1720        fn for_ptr<'db>(it: TyKind<'db>) -> Option<Ty<'db>> {1721            match it {1722                TyKind::RawPtr(ty, _) | TyKind::Ref(_, ty, _) => Some(ty),1723                _ => None,1724            }1725        }1726        let target_ty = self.coerce_unsized_look_through_fields(target_ty, for_ptr)?;1727        let current_ty = self.coerce_unsized_look_through_fields(current_ty, for_ptr)?;17281729        self.unsizing_ptr_from_addr(target_ty, current_ty, addr)1730    }17311732    /// Adds metadata to the address and create the fat pointer result of the unsizing operation.1733    fn unsizing_ptr_from_addr(1734        &mut self,1735        target_ty: Ty<'db>,1736        current_ty: Ty<'db>,1737        addr: Interval,1738    ) -> Result<'db, IntervalOrOwned> {1739        use IntervalOrOwned::*;1740        Ok(match &target_ty.kind() {1741            TyKind::Slice(_) => match &current_ty.kind() {1742                TyKind::Array(_, size) => {1743                    let len = match try_const_usize(self.db, *size) {1744                        None => {1745                            not_supported!("unevaluatble len of array in coerce unsized")1746                        }1747                        Some(it) => it as usize,1748                    };1749                    let mut r = Vec::with_capacity(16);1750                    let addr = addr.get(self)?;1751                    r.extend(addr.iter().copied());1752                    r.extend(len.to_le_bytes());1753                    Owned(r)1754                }1755                t => {1756                    not_supported!("slice unsizing from non array type {t:?}")1757                }1758            },1759            TyKind::Dynamic(..) => {1760                let vtable = self.vtable_map.id(current_ty);1761                let mut r = Vec::with_capacity(16);1762                let addr = addr.get(self)?;1763                r.extend(addr.iter().copied());1764                r.extend(vtable.to_le_bytes());1765                Owned(r)1766            }1767            TyKind::Adt(adt_def, target_subst) => match &current_ty.kind() {1768                TyKind::Adt(current_adt_def, current_subst) => {1769                    let id = adt_def.def_id();1770                    let current_id = current_adt_def.def_id();1771                    if id != current_id {1772                        not_supported!("unsizing struct with different type");1773                    }1774                    let id = match id {1775                        AdtId::StructId(s) => s,1776                        AdtId::UnionId(_) => not_supported!("unsizing unions"),1777                        AdtId::EnumId(_) => not_supported!("unsizing enums"),1778                    };1779                    let Some((last_field, _)) = id.fields(self.db).fields().iter().next_back()1780                    else {1781                        not_supported!("unsizing struct without field");1782                    };1783                    let target_last_field = self.db.field_types(id.into())[last_field]1784                        .ty()1785                        .instantiate(self.interner(), target_subst)1786                        .skip_norm_wip();1787                    let current_last_field = self.db.field_types(id.into())[last_field]1788                        .ty()1789                        .instantiate(self.interner(), current_subst)1790                        .skip_norm_wip();1791                    return self.unsizing_ptr_from_addr(1792                        target_last_field,1793                        current_last_field,1794                        addr,1795                    );1796                }1797                _ => not_supported!("unsizing struct with non adt type"),1798            },1799            _ => not_supported!("unknown unsized cast"),1800        })1801    }18021803    fn layout_of_variant(1804        &mut self,1805        it: VariantId,1806        subst: GenericArgs<'db>,1807        locals: &Locals<'a>,1808    ) -> Result<'db, (usize, Arc<Layout>, Option<(usize, usize, i128)>)> {1809        let adt = it.adt_id(self.db);1810        if let Some(f) = locals.body.owner.as_variant()1811            && let VariantId::EnumVariantId(it) = it1812            && let AdtId::EnumId(e) = adt1813            && f.lookup(self.db).parent == e1814        {1815            // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and1816            // infinite sized type errors) we use a dummy layout1817            let i = self.const_eval_discriminant(it)?;1818            return Ok((16, self.layout(Ty::new_empty_tuple(self.interner()))?, Some((0, 16, i))));1819        }1820        let layout = self.layout_adt(adt, subst)?;1821        Ok(match &layout.variants {1822            Variants::Single { .. } | Variants::Empty => (layout.size.bytes_usize(), layout, None),1823            Variants::Multiple { variants, tag, tag_encoding, .. } => {1824                let enum_variant_id = match it {1825                    VariantId::EnumVariantId(it) => it,1826                    _ => not_supported!("multi variant layout for non-enums"),1827                };1828                let mut discriminant = self.const_eval_discriminant(enum_variant_id)?;1829                let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.index(self.db));1830                let variant_layout = variants[rustc_enum_variant_idx].clone();1831                let have_tag = match tag_encoding {1832                    TagEncoding::Direct => true,1833                    TagEncoding::Niche { untagged_variant, niche_variants: _, niche_start } => {1834                        if *untagged_variant == rustc_enum_variant_idx {1835                            false1836                        } else {1837                            discriminant = (variants1838                                .iter_enumerated()1839                                .filter(|(it, _)| it != untagged_variant)1840                                .position(|(it, _)| it == rustc_enum_variant_idx)1841                                .unwrap() as i128)1842                                .wrapping_add(*niche_start as i128);1843                            true1844                        }1845                    }1846                };1847                (1848                    layout.size.bytes_usize(),1849                    Arc::new(variant_layout),1850                    if have_tag {1851                        Some((1852                            layout.fields.offset(0).bytes_usize(),1853                            tag.size(self.target_data_layout).bytes_usize(),1854                            discriminant,1855                        ))1856                    } else {1857                        None1858                    },1859                )1860            }1861        })1862    }18631864    fn construct_with_layout(1865        &mut self,1866        size: usize, // Not necessarily equal to variant_layout.size1867        variant_layout: &Layout,1868        tag: Option<(usize, usize, i128)>,1869        values: impl Iterator<Item = IntervalOrOwned>,1870    ) -> Result<'db, Vec<u8>> {1871        let mut result = vec![0; size];1872        if let Some((offset, size, value)) = tag {1873            match result.get_mut(offset..offset + size) {1874                Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),1875                None => {1876                    return Err(MirEvalError::InternalError(1877                        format!(1878                            "encoded tag ({offset}, {size}, {value}) is out of bounds 0..{size}"1879                        )1880                        .into(),1881                    ));1882                }1883            }1884        }1885        for (i, op) in values.enumerate() {1886            let offset = variant_layout.fields.offset(i).bytes_usize();1887            let op = op.get(self)?;1888            match result.get_mut(offset..offset + op.len()) {1889                Some(it) => it.copy_from_slice(op),1890                None => {1891                    return Err(MirEvalError::InternalError(1892                        format!("field offset ({offset}) is out of bounds 0..{size}").into(),1893                    ));1894                }1895            }1896        }1897        Ok(result)1898    }18991900    fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'a>) -> Result<'db, Interval> {1901        Ok(match &it.kind {1902            OperandKind::Copy(p) | OperandKind::Move(p) => {1903                locals.drop_flags.remove_place(p.as_ref());1904                self.eval_place(p, locals)?1905            }1906            OperandKind::Static(st) => {1907                let addr = self.eval_static(*st, locals)?;1908                Interval::new(addr, self.ptr_size())1909            }1910            OperandKind::Constant { konst, .. } => {1911                self.allocate_const_in_heap(locals, konst.as_ref())?1912            }1913            OperandKind::Allocation { allocation } => {1914                self.allocate_allocation_in_heap(locals, allocation.as_ref())?1915            }1916        })1917    }19181919    fn allocate_valtree_in_heap(1920        &mut self,1921        ty: Ty<'db>,1922        valtree: ValTree<'db>,1923    ) -> Result<'db, Interval> {1924        match ty.kind() {1925            TyKind::Bool => {1926                let value = valtree.inner().to_leaf().try_to_bool().unwrap();1927                let addr = self.heap_allocate(1, 1)?;1928                self.write_memory(addr, &[u8::from(value)])?;1929                Ok(Interval::new(addr, 1))1930            }1931            TyKind::Char => {1932                let value = valtree.inner().to_leaf().to_u32();1933                let addr = self.heap_allocate(4, 4)?;1934                self.write_memory(addr, &value.to_le_bytes())?;1935                Ok(Interval::new(addr, 4))1936            }1937            TyKind::Int(int_ty) => {1938                let size = int_ty.bit_width().unwrap_or(self.ptr_size() as u64);1939                let value = valtree.inner().to_leaf().to_int(Size::from_bytes(size));1940                let addr = self.heap_allocate(size as usize, size as usize)?;1941                self.write_memory(addr, &value.to_le_bytes()[..size as usize])?;1942                Ok(Interval::new(addr, size as usize))1943            }1944            TyKind::Uint(uint_ty) => {1945                let size = uint_ty.bit_width().unwrap_or(self.ptr_size() as u64);1946                let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size));1947                let addr = self.heap_allocate(size as usize, size as usize)?;1948                self.write_memory(addr, &value.to_le_bytes()[..size as usize])?;1949                Ok(Interval::new(addr, size as usize))1950            }1951            TyKind::Float(float_ty) => {1952                let size = float_ty.bit_width();1953                let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size));1954                let addr = self.heap_allocate(size as usize, size as usize)?;1955                self.write_memory(addr, &value.to_le_bytes()[..size as usize])?;1956                Ok(Interval::new(addr, size as usize))1957            }1958            TyKind::RawPtr(..) => {1959                let size = self.ptr_size();1960                let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size));1961                let addr = self.heap_allocate(size, size)?;1962                self.write_memory(addr, &value.to_le_bytes()[..size])?;1963                Ok(Interval::new(addr, size))1964            }1965            TyKind::Ref(_, inner_ty, _) => match inner_ty.kind() {1966                TyKind::Str => {1967                    let bytes = valtree1968                        .inner()1969                        .to_branch()1970                        .iter()1971                        .map(|konst| match konst.kind() {1972                            ConstKind::Value(value) => Ok(value.value.inner().to_leaf().to_u8()),1973                            _ => not_supported!("unsupported const"),1974                        })1975                        .collect::<Result<'_, Vec<_>>>()?;1976                    let bytes_addr = self.heap_allocate(bytes.len(), 1)?;1977                    self.write_memory(bytes_addr, &bytes)?;1978                    let ref_addr = self.heap_allocate(self.ptr_size() * 2, self.ptr_size())?;1979                    self.write_memory(ref_addr, &bytes_addr.to_bytes())?;1980                    let mut len = [0; 16];1981                    len[..size_of::<usize>()].copy_from_slice(&bytes.len().to_le_bytes());1982                    self.write_memory(ref_addr.offset(self.ptr_size()), &len[..self.ptr_size()])?;1983                    Ok(Interval::new(ref_addr, self.ptr_size() * 2))1984                }1985                TyKind::Slice(inner_ty) => {1986                    let item_layout = self.layout(inner_ty)?;1987                    let items = valtree1988                        .inner()1989                        .to_branch()1990                        .iter()1991                        .map(|konst| match konst.kind() {1992                            ConstKind::Value(value) => {1993                                self.allocate_valtree_in_heap(value.ty, value.value)1994                            }1995                            _ => not_supported!("unsupported const"),1996                        })1997                        .collect::<Result<'_, Vec<_>>>()?;1998                    let items_addr = self.heap_allocate(1999                        items.len() * (item_layout.size.bits() as usize),2000                        item_layout.align.bits_usize(),

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.