src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs RUST 2,406 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,406.
1//! This module generates a polymorphic MIR from a hir body23use std::{fmt::Write, iter, mem};45use base_db::Crate;6use hir_def::{7    AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, GenericParamId, HasModule,8    ItemContainerId, LocalFieldId, Lookup, TraitId,9    expr_store::{Body, ExpressionStore, HygieneId, path::Path},10    hir::{11        ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ClosureKind, ExprId, ExprOrPatId,12        LabelId, Literal, MatchArm, Pat, PatId, RecordLitField, RecordSpread,13        generics::GenericParams,14    },15    item_tree::FieldsShape,16    lang_item::LangItems,17    resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},18    signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature},19};20use hir_expand::name::Name;21use itertools::{EitherOrBoth, Itertools};22use la_arena::{ArenaMap, RawIdx};23use rustc_apfloat::Float;24use rustc_hash::FxHashMap;25use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _};26use span::{Edition, FileId};27use syntax::TextRange;2829use crate::{30    Adjust, Adjustment, AutoBorrow, CallableDefId, InferBodyId, ParamEnvAndCrate,31    consteval::ConstEvalError,32    db::{GeneralConstId, HirDatabase, InternedClosure, InternedClosureId},33    display::{DisplayTarget, HirDisplay, hir_display_with_store},34    generics::generics,35    infer::{36        CaptureSourceStack, CapturedPlace, UpvarCapture,37        cast::CastTy,38        closure::analysis::expr_use_visitor::{39            Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,40        },41    },42    inhabitedness::is_ty_uninhabited_from,43    layout::LayoutError,44    method_resolution::CandidateId,45    mir::{46        AggregateKind, Arena, BasicBlock, BasicBlockId, BinOp, BorrowKind, CastKind, Expr,47        FieldIndex, GenericArgs, Idx, InferenceResult, Local, LocalId, MemoryMap, MirBody, MirSpan,48        Mutability, Operand, Place, PlaceElem, PointerCast, Projection, ProjectionElem, Rvalue,49        Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, Ty, UnOp, VariantId,50        return_slot,51    },52    next_solver::{53        Const, DbInterner, ParamConst, ParamEnv, Region, StoredGenericArgs, StoredTy, TyKind,54        TypingMode, UnevaluatedConst,55        abi::Safety,56        infer::{DbInternerInferExt, InferCtxt},57    },58};5960use super::{OperandKind, PlaceRef};6162mod as_place;63mod pattern_matching;64#[cfg(test)]65mod tests;6667#[derive(Debug, Clone)]68struct LoopBlocks {69    begin: BasicBlockId,70    /// `None` for loops that are not terminating71    end: Option<BasicBlockId>,72    place: Place,73    drop_scope_index: usize,74}7576#[derive(Debug, Clone, Default)]77struct DropScope {78    /// locals, in order of definition (so we should run drop glues in reverse order)79    locals: Vec<LocalId>,80}8182struct MirLowerCtx<'a, 'db> {83    result: MirBody,84    owner: InferBodyId,85    store_owner: ExpressionStoreOwnerId,86    current_loop_blocks: Option<LoopBlocks>,87    labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>,88    discr_temp: Option<Place>,89    db: &'db dyn HirDatabase,90    store: &'a ExpressionStore,91    infer: &'a InferenceResult,92    types: &'db crate::next_solver::DefaultAny<'db>,93    resolver: Resolver<'db>,94    drop_scopes: Vec<DropScope>,95    env: ParamEnv<'db>,96    infcx: InferCtxt<'db>,97}9899// FIXME: Make this smaller, its stored in database queries100#[derive(Debug, Clone, PartialEq, Eq)]101pub enum MirLowerError {102    ConstEvalError(Box<str>, Box<ConstEvalError>),103    LayoutError(LayoutError),104    IncompleteExpr,105    IncompletePattern,106    /// Trying to lower a trait function, instead of an implementation107    TraitFunctionDefinition(TraitId, Name),108    UnresolvedName(String),109    RecordLiteralWithoutPath,110    UnresolvedMethod(String),111    UnresolvedField,112    UnsizedTemporary(StoredTy),113    MissingFunctionDefinition(InferBodyId, ExprId),114    HasErrors,115    /// This should never happen. Type mismatch should catch everything.116    TypeError(&'static str),117    NotSupported(String),118    ContinueWithoutLoop,119    BreakWithoutLoop,120    Loop,121    /// Something that should never happen and is definitely a bug, but we don't want to panic if it happened122    ImplementationError(String),123    LangItemNotFound,124    MutatingRvalue,125    UnresolvedLabel,126    UnresolvedUpvar(Place),127    InaccessibleLocal,128129    // monomorphization errors:130    GenericArgNotProvided(GenericParamId, StoredGenericArgs),131}132133/// A token to ensuring that each drop scope is popped at most once, thanks to the compiler that checks moves.134struct DropScopeToken;135impl DropScopeToken {136    fn pop_and_drop<'db>(137        self,138        ctx: &mut MirLowerCtx<'_, 'db>,139        current: BasicBlockId,140        span: MirSpan,141    ) -> BasicBlockId {142        std::mem::forget(self);143        ctx.pop_drop_scope_internal(current, span)144    }145146    /// It is useful when we want a drop scope is syntactically closed, but we don't want to execute any drop147    /// code. Either when the control flow is diverging (so drop code doesn't reached) or when drop is handled148    /// for us (for example a block that ended with a return statement. Return will drop everything, so the block shouldn't149    /// do anything)150    fn pop_assume_dropped(self, ctx: &mut MirLowerCtx<'_, '_>) {151        std::mem::forget(self);152        ctx.pop_drop_scope_assume_dropped_internal();153    }154}155156impl Drop for DropScopeToken {157    fn drop(&mut self) {}158}159160// Uncomment this to make `DropScopeToken` a drop bomb. Unfortunately we can't do this in release, since161// in cases that mir lowering fails, we don't handle (and don't need to handle) drop scopes so it will be162// actually reached. `pop_drop_scope_assert_finished` will also detect this case, but doesn't show useful163// stack trace.164//165// impl Drop for DropScopeToken {166//     fn drop(&mut self) {167//         never!("Drop scope doesn't popped");168//     }169// }170171impl MirLowerError {172    pub fn pretty_print(173        &self,174        f: &mut String,175        db: &dyn HirDatabase,176        span_formatter: impl Fn(FileId, TextRange) -> String,177        display_target: DisplayTarget,178    ) -> std::result::Result<(), std::fmt::Error> {179        match self {180            MirLowerError::ConstEvalError(name, e) => {181                writeln!(f, "In evaluating constant {name}")?;182                match &**e {183                    ConstEvalError::MirLowerError(e) => {184                        e.pretty_print(f, db, span_formatter, display_target)?185                    }186                    ConstEvalError::MirEvalError(e) => {187                        e.pretty_print(f, db, span_formatter, display_target)?188                    }189                }190            }191            MirLowerError::MissingFunctionDefinition(owner, it) => {192                let owner = owner.expression_store_owner(db);193                let store = ExpressionStore::of(db, owner);194                writeln!(195                    f,196                    "Missing function definition for {}",197                    hir_def::expr_store::pretty::print_expr_hir(198                        db,199                        store,200                        owner,201                        *it,202                        display_target.edition203                    )204                )?;205            }206            MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,207            MirLowerError::GenericArgNotProvided(id, subst) => {208                let param_name = match *id {209                    GenericParamId::TypeParamId(id) => {210                        GenericParams::of(db, id.parent())[id.local_id()].name().cloned()211                    }212                    GenericParamId::ConstParamId(id) => {213                        GenericParams::of(db, id.parent())[id.local_id()].name().cloned()214                    }215                    GenericParamId::LifetimeParamId(id) => {216                        Some(GenericParams::of(db, id.parent)[id.local_id].name.clone())217                    }218                };219                writeln!(220                    f,221                    "Generic arg not provided for {}",222                    param_name.unwrap_or(Name::missing()).display(db, display_target.edition)223                )?;224                writeln!(f, "Provided args: [")?;225                for g in subst.as_ref() {226                    write!(f, "    {},", g.display(db, display_target))?;227                }228                writeln!(f, "]")?;229            }230            MirLowerError::LayoutError(_)231            | MirLowerError::UnsizedTemporary(_)232            | MirLowerError::IncompleteExpr233            | MirLowerError::IncompletePattern234            | MirLowerError::InaccessibleLocal235            | MirLowerError::TraitFunctionDefinition(_, _)236            | MirLowerError::UnresolvedName(_)237            | MirLowerError::RecordLiteralWithoutPath238            | MirLowerError::UnresolvedMethod(_)239            | MirLowerError::UnresolvedField240            | MirLowerError::TypeError(_)241            | MirLowerError::NotSupported(_)242            | MirLowerError::ContinueWithoutLoop243            | MirLowerError::BreakWithoutLoop244            | MirLowerError::Loop245            | MirLowerError::ImplementationError(_)246            | MirLowerError::LangItemNotFound247            | MirLowerError::MutatingRvalue248            | MirLowerError::UnresolvedLabel249            | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?,250        }251        Ok(())252    }253}254255macro_rules! not_supported {256    ($it: expr) => {257        return Err(MirLowerError::NotSupported(format!($it)))258    };259}260261macro_rules! implementation_error {262    ($it: expr) => {{263        ::stdx::never!("MIR lower implementation bug: {}", format!($it));264        return Err(MirLowerError::ImplementationError(format!($it)));265    }};266}267268impl From<LayoutError> for MirLowerError {269    fn from(value: LayoutError) -> Self {270        MirLowerError::LayoutError(value)271    }272}273274impl MirLowerError {275    fn unresolved_path(276        db: &dyn HirDatabase,277        p: &Path,278        display_target: DisplayTarget,279        owner: ExpressionStoreOwnerId,280        store: &ExpressionStore,281    ) -> Self {282        Self::UnresolvedName(283            hir_display_with_store(p, owner, store).display(db, display_target).to_string(),284        )285    }286}287288type Result<'db, T> = std::result::Result<T, MirLowerError>;289290impl<'a, 'db> MirLowerCtx<'a, 'db> {291    fn new(292        db: &'db dyn HirDatabase,293        owner: InferBodyId,294        store: &'a ExpressionStore,295        infer: &'a InferenceResult,296    ) -> Self {297        let mut basic_blocks = Arena::new();298        let start_block = basic_blocks.alloc(BasicBlock {299            statements: vec![],300            terminator: None,301            is_cleanup: false,302        });303        let locals = Arena::new();304        let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new();305        let mir = MirBody {306            basic_blocks,307            locals,308            start_block,309            binding_locals,310            upvar_locals: FxHashMap::default(),311            param_locals: vec![],312            owner,313            closures: vec![],314        };315        let store_owner = owner.expression_store_owner(db);316        let resolver = owner.resolver(db);317        let env = db.trait_environment(owner.generic_def(db));318        let interner = DbInterner::new_with(db, resolver.krate());319        // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body?320        let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());321322        MirLowerCtx {323            result: mir,324            db,325            infer,326            store,327            types: crate::next_solver::default_types(db),328            owner,329            store_owner,330            resolver,331            current_loop_blocks: None,332            labeled_loop_blocks: Default::default(),333            discr_temp: None,334            drop_scopes: vec![DropScope::default()],335            env,336            infcx,337        }338    }339340    #[inline]341    fn interner(&self) -> DbInterner<'db> {342        self.infcx.interner343    }344345    #[inline]346    fn lang_items(&self) -> &'db LangItems {347        self.infcx.interner.lang_items()348    }349350    fn temp(&mut self, ty: Ty<'db>, current: BasicBlockId, span: MirSpan) -> Result<'db, LocalId> {351        if matches!(ty.kind(), TyKind::Slice(_) | TyKind::Dynamic(..)) {352            return Err(MirLowerError::UnsizedTemporary(ty.store()));353        }354        let l = self.result.locals.alloc(Local { ty: ty.store() });355        self.push_storage_live_for_local(l, current, span)?;356        Ok(l)357    }358359    fn lower_expr_to_some_operand(360        &mut self,361        expr_id: ExprId,362        current: BasicBlockId,363    ) -> Result<'db, Option<(Operand, BasicBlockId)>> {364        if !self.has_adjustments(expr_id)365            && let Expr::Literal(l) = &self.store[expr_id]366        {367            let ty = self.expr_ty_without_adjust(expr_id);368            return Ok(Some((self.lower_literal_to_operand(ty, l)?, current)));369        }370        let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else {371            return Ok(None);372        };373        Ok(Some((374            Operand { kind: OperandKind::Copy(p.store()), span: Some(expr_id.into()) },375            current,376        )))377    }378379    fn lower_expr_to_place_with_adjust(380        &mut self,381        expr_id: ExprId,382        place: PlaceRef<'db>,383        current: BasicBlockId,384        adjustments: &[Adjustment],385    ) -> Result<'db, Option<BasicBlockId>> {386        match adjustments.split_last() {387            Some((last, rest)) => match &last.kind {388                Adjust::NeverToAny => {389                    let temp = self.temp(self.types.types.never, current, MirSpan::Unknown)?;390                    self.lower_expr_to_place_with_adjust(expr_id, temp.into(), current, rest)391                }392                Adjust::Deref(_) => {393                    let Some((p, current)) =394                        self.lower_expr_as_place_with_adjust(current, expr_id, true, adjustments)?395                    else {396                        return Ok(None);397                    };398                    self.push_assignment(399                        current,400                        place,401                        Operand { kind: OperandKind::Copy(p.store()), span: None }.into(),402                        expr_id.into(),403                    );404                    Ok(Some(current))405                }406                Adjust::Borrow(AutoBorrow::Ref(m)) => self.lower_expr_to_place_with_borrow_adjust(407                    expr_id,408                    place,409                    current,410                    rest,411                    (*m).into(),412                ),413                Adjust::Borrow(AutoBorrow::RawPtr(m)) => {414                    self.lower_expr_to_place_with_borrow_adjust(expr_id, place, current, rest, *m)415                }416                Adjust::Pointer(cast) => {417                    let Some((p, current)) =418                        self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)?419                    else {420                        return Ok(None);421                    };422                    self.push_assignment(423                        current,424                        place,425                        Rvalue::Cast(426                            CastKind::PointerCoercion(*cast),427                            Operand { kind: OperandKind::Copy(p.store()), span: None },428                            last.target.clone(),429                        ),430                        expr_id.into(),431                    );432                    Ok(Some(current))433                }434            },435            None => self.lower_expr_to_place_without_adjust(expr_id, place, current),436        }437    }438439    fn lower_expr_to_place_with_borrow_adjust(440        &mut self,441        expr_id: ExprId,442        place: PlaceRef<'db>,443        current: BasicBlockId,444        rest: &[Adjustment],445        m: Mutability,446    ) -> Result<'db, Option<BasicBlockId>> {447        let Some((p, current)) =448            self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)?449        else {450            return Ok(None);451        };452        let bk = BorrowKind::from_rustc_mutability(m);453        self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into());454        Ok(Some(current))455    }456457    fn lower_expr_to_place(458        &mut self,459        expr_id: ExprId,460        place: PlaceRef<'db>,461        prev_block: BasicBlockId,462    ) -> Result<'db, Option<BasicBlockId>> {463        if let Some(adjustments) = self.infer.expr_adjustments.get(&expr_id) {464            return self.lower_expr_to_place_with_adjust(expr_id, place, prev_block, adjustments);465        }466        self.lower_expr_to_place_without_adjust(expr_id, place, prev_block)467    }468469    fn lower_expr_to_place_without_adjust(470        &mut self,471        expr_id: ExprId,472        place: PlaceRef<'db>,473        mut current: BasicBlockId,474    ) -> Result<'db, Option<BasicBlockId>> {475        match &self.store[expr_id] {476            Expr::OffsetOf(_) => {477                not_supported!("builtin#offset_of")478            }479            Expr::InlineAsm(_) => {480                not_supported!("builtin#asm")481            }482            Expr::Missing => {483                if let Some(f) = self.owner.as_function() {484                    let assoc = f.lookup(self.db);485                    if let ItemContainerId::TraitId(t) = assoc.container {486                        let name = &FunctionSignature::of(self.db, f).name;487                        return Err(MirLowerError::TraitFunctionDefinition(t, name.clone()));488                    }489                }490                Err(MirLowerError::IncompleteExpr)491            }492            Expr::Path(p) => {493                let pr =494                    if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) {495                        match assoc {496                            CandidateId::ConstId(c) => {497                                self.lower_const(c.into(), current, place, subst, expr_id.into())?;498                                return Ok(Some(current));499                            }500                            CandidateId::FunctionId(_) => {501                                // FnDefs are zero sized, no action is needed.502                                return Ok(Some(current));503                            }504                        }505                    } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {506                        match variant {507                            VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),508                            VariantId::StructId(s) => ValueNs::StructId(s),509                            VariantId::UnionId(_) => implementation_error!("Union variant as path"),510                        }511                    } else {512                        let resolver_guard =513                            self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);514                        let hygiene = self.store.expr_path_hygiene(expr_id);515                        let result = self516                            .resolver517                            .resolve_path_in_value_ns_fully(self.db, p, hygiene)518                            .ok_or_else(|| {519                                MirLowerError::unresolved_path(520                                    self.db,521                                    p,522                                    DisplayTarget::from_crate(self.db, self.krate()),523                                    self.owner.expression_store_owner(self.db),524                                    self.store,525                                )526                            })?;527                        self.resolver.reset_to_guard(resolver_guard);528                        result529                    };530                match pr {531                    ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => {532                        let Some((temp, current)) =533                            self.lower_expr_as_place_without_adjust(current, expr_id, false)?534                        else {535                            return Ok(None);536                        };537                        self.push_assignment(538                            current,539                            place,540                            Operand { kind: OperandKind::Copy(temp.store()), span: None }.into(),541                            expr_id.into(),542                        );543                        Ok(Some(current))544                    }545                    ValueNs::ConstId(const_id) => {546                        self.lower_const(547                            const_id.into(),548                            current,549                            place,550                            GenericArgs::empty(self.interner()),551                            expr_id.into(),552                        )?;553                        Ok(Some(current))554                    }555                    ValueNs::EnumVariantId(variant_id) => {556                        let variant_fields = variant_id.fields(self.db);557                        if variant_fields.shape == FieldsShape::Unit {558                            let ty = self.infer.expr_ty(expr_id);559                            current = self.lower_enum_variant(560                                variant_id,561                                current,562                                place,563                                ty,564                                Box::new([]),565                                expr_id.into(),566                            )?;567                        }568                        // Otherwise its a tuple like enum, treated like a zero sized function, so no action is needed569                        Ok(Some(current))570                    }571                    ValueNs::GenericParam(p) => {572                        let def = self.owner.generic_def(self.db);573                        let generics = generics(self.db, def);574                        let index = generics.type_or_const_param_idx(p.into());575                        self.push_assignment(576                            current,577                            place,578                            Rvalue::from(Operand {579                                kind: OperandKind::Constant {580                                    konst: Const::new_param(581                                        self.interner(),582                                        ParamConst { id: p, index },583                                    )584                                    .store(),585                                    ty: self.db.const_param_ty(p).store(),586                                },587                                span: None,588                            }),589                            expr_id.into(),590                        );591                        Ok(Some(current))592                    }593                    ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::ImplSelf(_) => {594                        // It's probably a unit struct or a zero sized function, so no action is needed.595                        Ok(Some(current))596                    }597                }598            }599            Expr::If { condition, then_branch, else_branch } => {600                let Some((discr, current)) =601                    self.lower_expr_to_some_operand(*condition, current)?602                else {603                    return Ok(None);604                };605                let start_of_then = self.new_basic_block();606                let end_of_then = self.lower_expr_to_place(*then_branch, place, start_of_then)?;607                let start_of_else = self.new_basic_block();608                let end_of_else = if let Some(else_branch) = else_branch {609                    self.lower_expr_to_place(*else_branch, place, start_of_else)?610                } else {611                    Some(start_of_else)612                };613                self.set_terminator(614                    current,615                    TerminatorKind::SwitchInt {616                        discr,617                        targets: SwitchTargets::static_if(1, start_of_then, start_of_else),618                    },619                    expr_id.into(),620                );621                Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into()))622            }623            Expr::Let { pat, expr } => {624                let Some((cond_place, current)) = self.lower_expr_as_place(current, *expr, true)?625                else {626                    return Ok(None);627                };628                self.push_fake_read(current, cond_place, expr_id.into());629                let resolver_guard =630                    self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);631                let (then_target, else_target) =632                    self.pattern_match(current, None, cond_place, *pat)?;633                self.resolver.reset_to_guard(resolver_guard);634                self.write_bytes_to_place(635                    then_target,636                    place,637                    Box::new([1]),638                    Ty::new_bool(self.interner()),639                    MirSpan::Unknown,640                )?;641                if let Some(else_target) = else_target {642                    self.write_bytes_to_place(643                        else_target,644                        place,645                        Box::new([0]),646                        Ty::new_bool(self.interner()),647                        MirSpan::Unknown,648                    )?;649                }650                Ok(self.merge_blocks(Some(then_target), else_target, expr_id.into()))651            }652            Expr::Unsafe { id: _, statements, tail } => {653                self.lower_block_to_place(statements, current, *tail, place, expr_id.into())654            }655            Expr::Block { id: _, statements, tail, label } => {656                if let Some(label) = label {657                    self.lower_loop(current, place, Some(*label), expr_id.into(), |this, begin| {658                        if let Some(current) = this.lower_block_to_place(659                            statements,660                            begin,661                            *tail,662                            place,663                            expr_id.into(),664                        )? {665                            let end = this.current_loop_end()?;666                            this.set_goto(current, end, expr_id.into());667                        }668                        Ok(())669                    })670                } else {671                    self.lower_block_to_place(statements, current, *tail, place, expr_id.into())672                }673            }674            Expr::Loop { body, label, source: _ } => {675                self.lower_loop(current, place, *label, expr_id.into(), |this, begin| {676                    let scope = this.push_drop_scope();677                    if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? {678                        current = scope.pop_and_drop(this, current, body.into());679                        this.set_goto(current, begin, expr_id.into());680                    } else {681                        scope.pop_assume_dropped(this);682                    }683                    Ok(())684                })685            }686            Expr::Call { callee, args, .. } => {687                if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {688                    let ty = Ty::new_fn_def(689                        self.interner(),690                        CallableDefId::FunctionId(func_id).into(),691                        generic_args,692                    );693                    let func = Operand::from_bytes(Box::default(), ty);694                    return self.lower_call_and_args(695                        func,696                        iter::once(*callee).chain(args.iter().copied()),697                        place,698                        current,699                        self.is_uninhabited(expr_id),700                        expr_id.into(),701                    );702                }703                let callee_ty = self.expr_ty_after_adjustments(*callee);704                match callee_ty.kind() {705                    TyKind::FnDef(..) => {706                        let func = Operand::from_bytes(Box::default(), callee_ty);707                        self.lower_call_and_args(708                            func,709                            args.iter().copied(),710                            place,711                            current,712                            self.is_uninhabited(expr_id),713                            expr_id.into(),714                        )715                    }716                    TyKind::FnPtr(..) => {717                        let Some((func, current)) =718                            self.lower_expr_to_some_operand(*callee, current)?719                        else {720                            return Ok(None);721                        };722                        self.lower_call_and_args(723                            func,724                            args.iter().copied(),725                            place,726                            current,727                            self.is_uninhabited(expr_id),728                            expr_id.into(),729                        )730                    }731                    TyKind::Closure(_, _) => {732                        not_supported!(733                            "method resolution not emitted for closure (Are Fn traits available?)"734                        );735                    }736                    TyKind::Error(_) => {737                        Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id))738                    }739                    _ => Err(MirLowerError::TypeError("function call on bad type")),740                }741            }742            Expr::MethodCall { receiver, args, method_name, .. } => {743                let (func_id, generic_args) =744                    self.infer.method_resolution(expr_id).ok_or_else(|| {745                        MirLowerError::UnresolvedMethod(746                            method_name.display(self.db, self.edition()).to_string(),747                        )748                    })?;749                let func = Operand::from_fn(self.db, func_id, generic_args);750                self.lower_call_and_args(751                    func,752                    iter::once(*receiver).chain(args.iter().copied()),753                    place,754                    current,755                    self.is_uninhabited(expr_id),756                    expr_id.into(),757                )758            }759            Expr::Match { expr, arms } => {760                let Some((cond_place, mut current)) =761                    self.lower_expr_as_place(current, *expr, true)?762                else {763                    return Ok(None);764                };765                self.push_fake_read(current, cond_place, expr_id.into());766                let mut end = None;767                let resolver_guard =768                    self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);769                for MatchArm { pat, guard, expr } in arms.iter() {770                    let (then, mut otherwise) =771                        self.pattern_match(current, None, cond_place, *pat)?;772                    let then = if let &Some(guard) = guard {773                        let next = self.new_basic_block();774                        let o = otherwise.get_or_insert_with(|| self.new_basic_block());775                        if let Some((discr, c)) = self.lower_expr_to_some_operand(guard, then)? {776                            self.set_terminator(777                                c,778                                TerminatorKind::SwitchInt {779                                    discr,780                                    targets: SwitchTargets::static_if(1, next, *o),781                                },782                                expr_id.into(),783                            );784                        }785                        next786                    } else {787                        then788                    };789                    if let Some(block) = self.lower_expr_to_place(*expr, place, then)? {790                        let r = end.get_or_insert_with(|| self.new_basic_block());791                        self.set_goto(block, *r, expr_id.into());792                    }793                    match otherwise {794                        Some(o) => current = o,795                        None => {796                            // The current pattern was irrefutable, so there is no need to generate code797                            // for the rest of patterns798                            break;799                        }800                    }801                }802                self.resolver.reset_to_guard(resolver_guard);803                if self.is_unterminated(current) {804                    self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into());805                }806                Ok(end)807            }808            Expr::Continue { label } => {809                let loop_data = match label {810                    Some(l) => {811                        self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?812                    }813                    None => self814                        .current_loop_blocks815                        .as_ref()816                        .ok_or(MirLowerError::ContinueWithoutLoop)?,817                };818                let begin = loop_data.begin;819                current =820                    self.drop_until_scope(loop_data.drop_scope_index, current, expr_id.into());821                self.set_goto(current, begin, expr_id.into());822                Ok(None)823            }824            &Expr::Break { expr, label } => {825                if let Some(expr) = expr {826                    let loop_data = match label {827                        Some(l) => self828                            .labeled_loop_blocks829                            .get(&l)830                            .ok_or(MirLowerError::UnresolvedLabel)?,831                        None => self832                            .current_loop_blocks833                            .as_ref()834                            .ok_or(MirLowerError::BreakWithoutLoop)?,835                    };836                    let Some(c) =837                        self.lower_expr_to_place(expr, loop_data.place.as_ref(), current)?838                    else {839                        return Ok(None);840                    };841                    current = c;842                }843                let (end, drop_scope) = match label {844                    Some(l) => {845                        let loop_blocks = self846                            .labeled_loop_blocks847                            .get(&l)848                            .ok_or(MirLowerError::UnresolvedLabel)?;849                        (850                            loop_blocks.end.expect("We always generate end for labeled loops"),851                            loop_blocks.drop_scope_index,852                        )853                    }854                    None => (855                        self.current_loop_end()?,856                        self.current_loop_blocks.as_ref().unwrap().drop_scope_index,857                    ),858                };859                current = self.drop_until_scope(drop_scope, current, expr_id.into());860                self.set_goto(current, end, expr_id.into());861                Ok(None)862            }863            Expr::Return { expr } => {864                if let Some(expr) = expr {865                    if let Some(c) =866                        self.lower_expr_to_place(*expr, return_slot().into(), current)?867                    {868                        current = c;869                    } else {870                        return Ok(None);871                    }872                }873                current = self.drop_until_scope(0, current, expr_id.into());874                self.set_terminator(current, TerminatorKind::Return, expr_id.into());875                Ok(None)876            }877            Expr::Become { .. } => not_supported!("tail-calls"),878            Expr::Yield { .. } => not_supported!("yield"),879            Expr::RecordLit { fields, path, spread, .. } => {880                let spread_place = match *spread {881                    RecordSpread::Expr(it) => {882                        let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else {883                            return Ok(None);884                        };885                        current = c;886                        Some(p)887                    }888                    RecordSpread::None => None,889                    RecordSpread::FieldDefaults => not_supported!("empty record spread"),890                };891                let variant_id =892                    self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| {893                        MirLowerError::unresolved_path(894                            self.db,895                            path,896                            self.display_target(),897                            self.owner.expression_store_owner(self.db),898                            self.store,899                        )900                    })?;901                let subst = match self.expr_ty_without_adjust(expr_id).kind() {902                    TyKind::Adt(_, s) => s,903                    _ => not_supported!("Non ADT record literal"),904                };905                let variant_fields = variant_id.fields(self.db);906                match variant_id {907                    VariantId::EnumVariantId(_) | VariantId::StructId(_) => {908                        let mut operands = vec![None; variant_fields.fields().len()];909                        for RecordLitField { name, expr } in fields.iter() {910                            let field_id =911                                variant_fields.field(name).ok_or(MirLowerError::UnresolvedField)?;912                            let Some((op, c)) = self.lower_expr_to_some_operand(*expr, current)?913                            else {914                                return Ok(None);915                            };916                            current = c;917                            operands[u32::from(field_id.into_raw()) as usize] = Some(op);918                        }919                        let rvalue = Rvalue::Aggregate(920                            AggregateKind::Adt(variant_id, subst.store()),921                            match spread_place {922                                Some(sp) if let VariantId::StructId(_) = variant_id => operands923                                    .into_iter()924                                    .enumerate()925                                    .map(|(i, it)| match it {926                                        Some(it) => it,927                                        None => {928                                            let p = sp.project(ProjectionElem::Field(FieldIndex(929                                                i as u32,930                                            )));931                                            Operand {932                                                kind: OperandKind::Copy(p.store()),933                                                span: None,934                                            }935                                        }936                                    })937                                    .collect(),938                                Some(_) => {939                                    return Err(MirLowerError::TypeError(940                                        "functional record update syntax requires a struct",941                                    ));942                                }943                                None => operands.into_iter().collect::<Option<_>>().ok_or(944                                    MirLowerError::TypeError("missing field in record literal"),945                                )?,946                            },947                        );948                        self.push_assignment(current, place, rvalue, expr_id.into());949                        Ok(Some(current))950                    }951                    VariantId::UnionId(_union_id) => {952                        let [RecordLitField { name, expr }] = fields.as_ref() else {953                            not_supported!("Union record literal with more than one field");954                        };955                        let local_id =956                            variant_fields.field(name).ok_or(MirLowerError::UnresolvedField)?;957                        let place = place.project(PlaceElem::Field(local_id.into()));958                        self.lower_expr_to_place(*expr, place, current)959                    }960                }961            }962            Expr::Await { .. } => not_supported!("await"),963            Expr::Yeet { .. } => not_supported!("yeet"),964            &Expr::Const(_) => {965                // let subst = self.placeholder_subst();966                // self.lower_const(967                //     id.into(),968                //     current,969                //     place,970                //     subst,971                //     expr_id.into(),972                //     self.expr_ty_without_adjust(expr_id),973                // )?;974                // Ok(Some(current))975                not_supported!("const block")976            }977            Expr::Cast { expr, type_ref: _ } => {978                let Some((it, current)) = self.lower_expr_to_some_operand(*expr, current)? else {979                    return Ok(None);980                };981                // Since we don't have THIR, this is the "zipped" version of [rustc's HIR lowering](https://github.com/rust-lang/rust/blob/e71f9529121ca8f687e4b725e3c9adc3f1ebab4d/compiler/rustc_mir_build/src/thir/cx/expr.rs#L165-L178)982                // and [THIR lowering as RValue](https://github.com/rust-lang/rust/blob/a4601859ae3875732797873612d424976d9e3dd0/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs#L193-L313)983                let rvalue = if self.infer.coercion_casts.contains(expr) {984                    Rvalue::Use(it)985                } else {986                    let source_ty = self.infer.expr_ty(*expr);987                    let target_ty = self.infer.expr_ty(expr_id);988                    let cast_kind = if source_ty.as_reference().is_some() {989                        CastKind::PointerCoercion(PointerCast::ArrayToPointer)990                    } else {991                        cast_kind(self.db, source_ty, target_ty)?992                    };993994                    Rvalue::Cast(cast_kind, it, target_ty.store())995                };996                self.push_assignment(current, place, rvalue, expr_id.into());997                Ok(Some(current))998            }999            Expr::Ref { expr, rawness: _, mutability } => {1000                let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? else {1001                    return Ok(None);1002                };1003                let bk = BorrowKind::from_hir_mutability(*mutability);1004                self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into());1005                Ok(Some(current))1006            }1007            Expr::Box { expr } => {1008                let ty = self.expr_ty_after_adjustments(*expr);1009                self.push_assignment(1010                    current,1011                    place,1012                    Rvalue::ShallowInitBoxWithAlloc(ty.store()),1013                    expr_id.into(),1014                );1015                let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)?1016                else {1017                    return Ok(None);1018                };1019                let p = place.project(ProjectionElem::Deref);1020                self.push_assignment(current, p, operand.into(), expr_id.into());1021                Ok(Some(current))1022            }1023            Expr::Field { .. }1024            | Expr::Index { .. }1025            | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => {1026                let Some((p, current)) =1027                    self.lower_expr_as_place_without_adjust(current, expr_id, true)?1028                else {1029                    return Ok(None);1030                };1031                self.push_assignment(1032                    current,1033                    place,1034                    Operand { kind: OperandKind::Copy(p.store()), span: None }.into(),1035                    expr_id.into(),1036                );1037                Ok(Some(current))1038            }1039            Expr::UnaryOp {1040                expr,1041                op: op @ (hir_def::hir::UnaryOp::Not | hir_def::hir::UnaryOp::Neg),1042            } => {1043                let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)?1044                else {1045                    return Ok(None);1046                };1047                let operation = match op {1048                    hir_def::hir::UnaryOp::Not => UnOp::Not,1049                    hir_def::hir::UnaryOp::Neg => UnOp::Neg,1050                    _ => unreachable!(),1051                };1052                self.push_assignment(1053                    current,1054                    place,1055                    Rvalue::UnaryOp(operation, operand),1056                    expr_id.into(),1057                );1058                Ok(Some(current))1059            }1060            Expr::BinaryOp { lhs, rhs, op } => {1061                let op: BinaryOp = op.ok_or(MirLowerError::IncompleteExpr)?;1062                let is_builtin = 'b: {1063                    // Without adjust here is a hack. We assume that we know every possible adjustment1064                    // for binary operator, and use without adjust to simplify our conditions.1065                    let lhs_ty = self.expr_ty_without_adjust(*lhs);1066                    let rhs_ty = self.expr_ty_without_adjust(*rhs);1067                    if matches!(op, BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. }))1068                        && matches!(lhs_ty.kind(), TyKind::RawPtr(..))1069                        && matches!(rhs_ty.kind(), TyKind::RawPtr(..))1070                    {1071                        break 'b true;1072                    }1073                    let builtin_inequal_impls = matches!(1074                        op,1075                        BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr)1076                            | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) }1077                    );1078                    matches!(1079                        lhs_ty.kind(),1080                        TyKind::Bool1081                            | TyKind::Char1082                            | TyKind::Int(_)1083                            | TyKind::Uint(_)1084                            | TyKind::Float(_)1085                    ) && matches!(1086                        rhs_ty.kind(),1087                        TyKind::Bool1088                            | TyKind::Char1089                            | TyKind::Int(_)1090                            | TyKind::Uint(_)1091                            | TyKind::Float(_)1092                    ) && (lhs_ty == rhs_ty || builtin_inequal_impls)1093                };1094                if !is_builtin1095                    && let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id)1096                {1097                    let func = Operand::from_fn(self.db, func_id, generic_args);1098                    return self.lower_call_and_args(1099                        func,1100                        [*lhs, *rhs].into_iter(),1101                        place,1102                        current,1103                        self.is_uninhabited(expr_id),1104                        expr_id.into(),1105                    );1106                }1107                if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op {1108                    // last adjustment is `&mut` which we don't want it.1109                    let adjusts = self1110                        .infer1111                        .expr_adjustments1112                        .get(lhs)1113                        .and_then(|it| it.split_last())1114                        .map(|it| it.1)1115                        .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?;1116                    let Some((lhs_place, current)) =1117                        self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?1118                    else {1119                        return Ok(None);1120                    };1121                    let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)?1122                    else {1123                        return Ok(None);1124                    };1125                    let r_value = Rvalue::CheckedBinaryOp(1126                        op.into(),1127                        Operand { kind: OperandKind::Copy(lhs_place.store()), span: None },1128                        rhs_op,1129                    );1130                    self.push_assignment(current, lhs_place, r_value, expr_id.into());1131                    return Ok(Some(current));1132                }1133                let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)?1134                else {1135                    return Ok(None);1136                };1137                if let hir_def::hir::BinaryOp::LogicOp(op) = op {1138                    let value_to_short = match op {1139                        syntax::ast::LogicOp::And => 0,1140                        syntax::ast::LogicOp::Or => 1,1141                    };1142                    let start_of_then = self.new_basic_block();1143                    self.push_assignment(1144                        start_of_then,1145                        place,1146                        lhs_op.clone().into(),1147                        expr_id.into(),1148                    );1149                    let end_of_then = Some(start_of_then);1150                    let start_of_else = self.new_basic_block();1151                    let end_of_else = self.lower_expr_to_place(*rhs, place, start_of_else)?;1152                    self.set_terminator(1153                        current,1154                        TerminatorKind::SwitchInt {1155                            discr: lhs_op,1156                            targets: SwitchTargets::static_if(1157                                value_to_short,1158                                start_of_then,1159                                start_of_else,1160                            ),1161                        },1162                        expr_id.into(),1163                    );1164                    return Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into()));1165                }1166                let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)?1167                else {1168                    return Ok(None);1169                };1170                self.push_assignment(1171                    current,1172                    place,1173                    Rvalue::CheckedBinaryOp(1174                        match op {1175                            hir_def::hir::BinaryOp::LogicOp(op) => match op {1176                                hir_def::hir::LogicOp::And => BinOp::BitAnd, // FIXME: make these short circuit1177                                hir_def::hir::LogicOp::Or => BinOp::BitOr,1178                            },1179                            hir_def::hir::BinaryOp::ArithOp(op) => BinOp::from(op),1180                            hir_def::hir::BinaryOp::CmpOp(op) => BinOp::from(op),1181                            hir_def::hir::BinaryOp::Assignment { .. } => unreachable!(), // handled above1182                        },1183                        lhs_op,1184                        rhs_op,1185                    ),1186                    expr_id.into(),1187                );1188                Ok(Some(current))1189            }1190            &Expr::Assignment { target, value } => {1191                let Some((value, mut current)) = self.lower_expr_as_place(current, value, true)?1192                else {1193                    return Ok(None);1194                };1195                self.push_fake_read(current, value, expr_id.into());1196                let resolver_guard =1197                    self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);1198                current = self.pattern_match_assignment(current, value, target)?;1199                self.resolver.reset_to_guard(resolver_guard);1200                Ok(Some(current))1201            }1202            &Expr::Range { lhs, rhs, range_type: _ } => {1203                let ty = self.expr_ty_without_adjust(expr_id);1204                let Some((adt, subst)) = ty.as_adt() else {1205                    return Err(MirLowerError::TypeError("Range type is not adt"));1206                };1207                let AdtId::StructId(st) = adt else {1208                    return Err(MirLowerError::TypeError("Range type is not struct"));1209                };1210                let mut lp = None;1211                let mut rp = None;1212                if let Some(it) = lhs {1213                    let Some((o, c)) = self.lower_expr_to_some_operand(it, current)? else {1214                        return Ok(None);1215                    };1216                    lp = Some(o);1217                    current = c;1218                }1219                if let Some(it) = rhs {1220                    let Some((o, c)) = self.lower_expr_to_some_operand(it, current)? else {1221                        return Ok(None);1222                    };1223                    rp = Some(o);1224                    current = c;1225                }1226                self.push_assignment(1227                    current,1228                    place,1229                    Rvalue::Aggregate(1230                        AggregateKind::Adt(st.into(), subst.store()),1231                        st.fields(self.db)1232                            .fields()1233                            .iter()1234                            .map(|it| {1235                                let o = match it.1.name.as_str() {1236                                    "start" => lp.take(),1237                                    "end" => rp.take(),1238                                    "exhausted" => Some(Operand::from_bytes(1239                                        Box::new([0]),1240                                        Ty::new_bool(self.interner()),1241                                    )),1242                                    _ => None,1243                                };1244                                o.ok_or(MirLowerError::UnresolvedField)1245                            })1246                            .collect::<Result<'_, _>>()?,1247                    ),1248                    expr_id.into(),1249                );1250                Ok(Some(current))1251            }1252            Expr::Closure { closure_kind: ClosureKind::Closure, .. } => {1253                let ty = self.expr_ty_without_adjust(expr_id);1254                let TyKind::Closure(id, _) = ty.kind() else {1255                    not_supported!("closure with non closure type");1256                };1257                self.result.closures.push(id.0);1258                let closure_data = &self.infer.closures_data[&id.0.loc(self.db).expr];12591260                let span = |sources: &[CaptureSourceStack]| match sources1261                    .first()1262                    .map(|it| it.final_source())1263                {1264                    Some(ExprOrPatId::ExprId(it)) => it.into(),1265                    Some(ExprOrPatId::PatId(it)) => it.into(),1266                    None => MirSpan::Unknown,1267                };1268                let convert_place = |this: &mut Self, place: &HirPlace| {1269                    let (HirPlaceBase::Local(local) | HirPlaceBase::Upvar { var_id: local, .. }) =1270                        place.base1271                    else {1272                        not_supported!("non-local capture");1273                    };1274                    Ok(Place {1275                        local: this.binding_local(local)?,1276                        projection: Projection::new_from_iter(convert_closure_capture_projections(1277                            self.db, place,1278                        ))1279                        .store(),1280                    })1281                };12821283                for (place, _, sources) in &closure_data.fake_reads {1284                    let p = convert_place(self, place)?;1285                    self.push_fake_read(current, p.as_ref(), span(sources));1286                }12871288                let captures = closure_data.min_captures.values().flatten();1289                let mut operands = vec![];1290                for capture in captures {1291                    let p = convert_place(self, &capture.place)?;1292                    match capture.info.capture_kind {1293                        UpvarCapture::ByRef(bk) => {1294                            let tmp_ty = capture.captured_ty(self.db);1295                            // FIXME: Handle more than one span.1296                            let capture_span = span(&capture.info.sources);1297                            let tmp = self.temp(tmp_ty, current, capture_span)?.into();1298                            self.push_assignment(1299                                current,1300                                tmp,1301                                Rvalue::Ref(BorrowKind::from_hir(bk), p),1302                                capture_span,1303                            );1304                            operands1305                                .push(Operand { kind: OperandKind::Move(tmp.store()), span: None });1306                        }1307                        UpvarCapture::ByValue => {1308                            operands.push(Operand { kind: OperandKind::Move(p), span: None })1309                        }1310                        UpvarCapture::ByUse => not_supported!("capture by use"),1311                    }1312                }1313                self.push_assignment(1314                    current,1315                    place,1316                    Rvalue::Aggregate(AggregateKind::Closure(ty.store()), operands.into()),1317                    expr_id.into(),1318                );1319                Ok(Some(current))1320            }1321            Expr::Closure { closure_kind, .. } => not_supported!("{closure_kind:?} closure"),1322            Expr::Tuple { exprs } => {1323                let Some(values) = exprs1324                    .iter()1325                    .map(|it| {1326                        let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)? else {1327                            return Ok(None);1328                        };1329                        current = c;1330                        Ok(Some(o))1331                    })1332                    .collect::<Result<'_, Option<_>>>()?1333                else {1334                    return Ok(None);1335                };1336                let r = Rvalue::Aggregate(1337                    AggregateKind::Tuple(self.expr_ty_without_adjust(expr_id).store()),1338                    values,1339                );1340                self.push_assignment(current, place, r, expr_id.into());1341                Ok(Some(current))1342            }1343            Expr::Array(l) => match l {1344                Array::ElementList { elements, .. } => {1345                    let elem_ty = match self.expr_ty_without_adjust(expr_id).kind() {1346                        TyKind::Array(ty, _) => ty,1347                        _ => {1348                            return Err(MirLowerError::TypeError(1349                                "Array expression with non array type",1350                            ));1351                        }1352                    };1353                    let Some(values) = elements1354                        .iter()1355                        .map(|it| {1356                            let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)?1357                            else {1358                                return Ok(None);1359                            };1360                            current = c;1361                            Ok(Some(o))1362                        })1363                        .collect::<Result<'_, Option<_>>>()?1364                    else {1365                        return Ok(None);1366                    };1367                    let r = Rvalue::Aggregate(AggregateKind::Array(elem_ty.store()), values);1368                    self.push_assignment(current, place, r, expr_id.into());1369                    Ok(Some(current))1370                }1371                Array::Repeat { initializer, .. } => {1372                    let Some((init, current)) =1373                        self.lower_expr_to_some_operand(*initializer, current)?1374                    else {1375                        return Ok(None);1376                    };1377                    let len = match self.expr_ty_without_adjust(expr_id).kind() {1378                        TyKind::Array(_, len) => len,1379                        _ => {1380                            return Err(MirLowerError::TypeError(1381                                "Array repeat expression with non array type",1382                            ));1383                        }1384                    };1385                    let r = Rvalue::Repeat(init, len.store());1386                    self.push_assignment(current, place, r, expr_id.into());1387                    Ok(Some(current))1388                }1389            },1390            Expr::Literal(l) => {1391                let ty = self.expr_ty_without_adjust(expr_id);1392                let op = self.lower_literal_to_operand(ty, l)?;1393                self.push_assignment(current, place, op.into(), expr_id.into());1394                Ok(Some(current))1395            }1396            Expr::Underscore => Ok(Some(current)),1397            Expr::IncludeBytes => not_supported!("include_bytes!()"),1398        }1399    }14001401    fn push_field_projection(1402        &mut self,1403        place: &mut PlaceRef<'db>,1404        expr_id: ExprId,1405    ) -> Result<'db, ()> {1406        if let Expr::Field { expr, name } = &self.store[expr_id] {1407            if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind() {1408                let index =1409                    name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))?1410                        as u32;1411                *place = place.project(ProjectionElem::Field(FieldIndex(index)))1412            } else {1413                let field = self1414                    .infer1415                    .field_resolution(expr_id)1416                    .ok_or(MirLowerError::UnresolvedField)?1417                    .either(|f| f.local_id.into(), |t| FieldIndex(t.index));1418                *place = place.project(ProjectionElem::Field(field));1419            }1420        } else {1421            not_supported!("")1422        }1423        Ok(())1424    }14251426    fn lower_literal_or_const_to_operand(1427        &mut self,1428        ty: Ty<'db>,1429        loc: &ExprId,1430    ) -> Result<'db, Operand> {1431        match &self.store[*loc] {1432            Expr::Literal(l) => self.lower_literal_to_operand(ty, l),1433            Expr::Path(c) => {1434                let owner = self.owner;1435                let db = self.db;1436                let unresolved_name = || {1437                    MirLowerError::unresolved_path(1438                        self.db,1439                        c,1440                        DisplayTarget::from_crate(db, owner.krate(db)),1441                        self.owner.expression_store_owner(self.db),1442                        self.store,1443                    )1444                };1445                let pr = self1446                    .resolver1447                    .resolve_path_in_value_ns(self.db, c, HygieneId::ROOT)1448                    .ok_or_else(unresolved_name)?;1449                match pr {1450                    ResolveValueResult::ValueNs(v) => {1451                        if let ValueNs::ConstId(c) = v {1452                            self.lower_const_to_operand(1453                                GenericArgs::empty(self.interner()),1454                                c.into(),1455                            )1456                        } else {1457                            not_supported!("bad path in range pattern");1458                        }1459                    }1460                    ResolveValueResult::Partial(_, _) => {1461                        not_supported!("associated constants in range pattern")1462                    }1463                }1464            }1465            _ => {1466                not_supported!("only `char` and numeric types are allowed in range patterns");1467            }1468        }1469    }14701471    fn lower_literal_to_operand(&mut self, ty: Ty<'db>, l: &Literal) -> Result<'db, Operand> {1472        let size = || {1473            self.db1474                .layout_of_ty(1475                    ty.store(),1476                    ParamEnvAndCrate { param_env: self.env, krate: self.krate() }.store(),1477                )1478                .map(|it| it.size.bytes_usize())1479        };1480        const USIZE_SIZE: usize = size_of::<usize>();1481        let bytes: Box<[_]> = match l {1482            hir_def::hir::Literal::String(b) => {1483                let b = b.as_str();1484                let mut data = [0; { 2 * USIZE_SIZE }];1485                data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes());1486                data[USIZE_SIZE..].copy_from_slice(&b.len().to_le_bytes());1487                let mm = MemoryMap::simple(b.as_bytes().into());1488                return Ok(Operand::from_concrete_const(Box::new(data), mm, ty));1489            }1490            hir_def::hir::Literal::CString(b) => {1491                let bytes = b.iter().copied().chain(iter::once(0)).collect::<Box<_>>();14921493                let mut data = [0; { 2 * USIZE_SIZE }];1494                data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes());1495                data[USIZE_SIZE..].copy_from_slice(&bytes.len().to_le_bytes());1496                let mm = MemoryMap::simple(bytes);1497                return Ok(Operand::from_concrete_const(Box::new(data), mm, ty));1498            }1499            hir_def::hir::Literal::ByteString(b) => {1500                let mut data = [0; { 2 * USIZE_SIZE }];1501                data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes());1502                data[USIZE_SIZE..].copy_from_slice(&b.len().to_le_bytes());1503                let mm = MemoryMap::simple(b.clone());1504                return Ok(Operand::from_concrete_const(Box::new(data), mm, ty));1505            }1506            hir_def::hir::Literal::Char(c) => Box::new(u32::from(*c).to_le_bytes()),1507            hir_def::hir::Literal::Bool(b) => Box::new([*b as u8]),1508            hir_def::hir::Literal::Int(it, _) => Box::from(&it.to_le_bytes()[0..size()?]),1509            hir_def::hir::Literal::Uint(it, _) => Box::from(&it.to_le_bytes()[0..size()?]),1510            hir_def::hir::Literal::Float(f, _) => match size()? {1511                16 => Box::new(f.to_f128().to_bits().to_le_bytes()),1512                8 => Box::new(f.to_f64().to_bits().to_le_bytes()),1513                4 => Box::new(f.to_f32().to_bits().to_le_bytes()),1514                2 => Box::new(u16::try_from(f.to_f16().to_bits()).unwrap().to_le_bytes()),1515                _ => {1516                    return Err(MirLowerError::TypeError(1517                        "float with size other than 2, 4, 8 or 16 bytes",1518                    ));1519                }1520            },1521        };1522        Ok(Operand::from_concrete_const(bytes, MemoryMap::default(), ty))1523    }15241525    fn new_basic_block(&mut self) -> BasicBlockId {1526        self.result.basic_blocks.alloc(BasicBlock::default())1527    }15281529    fn lower_const(1530        &mut self,1531        const_id: GeneralConstId,1532        prev_block: BasicBlockId,1533        place: PlaceRef<'db>,1534        subst: GenericArgs<'db>,1535        span: MirSpan,1536    ) -> Result<'db, ()> {1537        let c = self.lower_const_to_operand(subst, const_id)?;1538        self.push_assignment(prev_block, place, c.into(), span);1539        Ok(())1540    }15411542    fn lower_const_to_operand(1543        &mut self,1544        subst: GenericArgs<'db>,1545        const_id: GeneralConstId,1546    ) -> Result<'db, Operand> {1547        let konst = Const::new_unevaluated(1548            self.interner(),1549            UnevaluatedConst { def: const_id.into(), args: subst },1550        );1551        let ty = match const_id {1552            GeneralConstId::ConstId(id) => self.db.value_ty(id.into()).unwrap(),1553            GeneralConstId::StaticId(id) => self.db.value_ty(id.into()).unwrap(),1554            GeneralConstId::AnonConstId(id) => id.loc(self.db).ty.get(),1555        };1556        let ty = ty.instantiate(self.interner(), subst).skip_norm_wip();1557        Ok(Operand {1558            kind: OperandKind::Constant { konst: konst.store(), ty: ty.store() },1559            span: None,1560        })1561    }15621563    fn write_bytes_to_place(1564        &mut self,1565        prev_block: BasicBlockId,1566        place: PlaceRef<'db>,1567        cv: Box<[u8]>,1568        ty: Ty<'db>,1569        span: MirSpan,1570    ) -> Result<'db, ()> {1571        self.push_assignment(prev_block, place, Operand::from_bytes(cv, ty).into(), span);1572        Ok(())1573    }15741575    fn lower_enum_variant(1576        &mut self,1577        variant_id: EnumVariantId,1578        prev_block: BasicBlockId,1579        place: PlaceRef<'db>,1580        ty: Ty<'db>,1581        fields: Box<[Operand]>,1582        span: MirSpan,1583    ) -> Result<'db, BasicBlockId> {1584        let subst = match ty.kind() {1585            TyKind::Adt(_, subst) => subst,1586            _ => implementation_error!("Non ADT enum"),1587        };1588        self.push_assignment(1589            prev_block,1590            place,1591            Rvalue::Aggregate(AggregateKind::Adt(variant_id.into(), subst.store()), fields),1592            span,1593        );1594        Ok(prev_block)1595    }15961597    fn lower_call_and_args(1598        &mut self,1599        func: Operand,1600        args: impl Iterator<Item = ExprId>,1601        place: PlaceRef<'db>,1602        mut current: BasicBlockId,1603        is_uninhabited: bool,1604        span: MirSpan,1605    ) -> Result<'db, Option<BasicBlockId>> {1606        let Some(args) = args1607            .map(|arg| {1608                if let Some((temp, c)) = self.lower_expr_to_some_operand(arg, current)? {1609                    current = c;1610                    Ok(Some(temp))1611                } else {1612                    Ok(None)1613                }1614            })1615            .collect::<Result<'_, Option<Vec<_>>>>()?1616        else {1617            return Ok(None);1618        };1619        self.lower_call(func, args.into(), place, current, is_uninhabited, span)1620    }16211622    fn lower_call(1623        &mut self,1624        func: Operand,1625        args: Box<[Operand]>,1626        place: PlaceRef<'db>,1627        current: BasicBlockId,1628        is_uninhabited: bool,1629        span: MirSpan,1630    ) -> Result<'db, Option<BasicBlockId>> {1631        let b = if is_uninhabited { None } else { Some(self.new_basic_block()) };1632        self.set_terminator(1633            current,1634            TerminatorKind::Call {1635                func,1636                args,1637                destination: place.store(),1638                target: b,1639                cleanup: None,1640                from_hir_call: true,1641            },1642            span,1643        );1644        Ok(b)1645    }16461647    fn is_unterminated(&mut self, source: BasicBlockId) -> bool {1648        self.result.basic_blocks[source].terminator.is_none()1649    }16501651    fn set_terminator(&mut self, source: BasicBlockId, terminator: TerminatorKind, span: MirSpan) {1652        self.result.basic_blocks[source].terminator = Some(Terminator { span, kind: terminator });1653    }16541655    fn set_goto(&mut self, source: BasicBlockId, target: BasicBlockId, span: MirSpan) {1656        self.set_terminator(source, TerminatorKind::Goto { target }, span);1657    }16581659    fn expr_ty_without_adjust(&self, e: ExprId) -> Ty<'db> {1660        self.infer.expr_ty(e)1661    }16621663    fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty<'db> {1664        let mut ty = None;1665        if let Some(it) = self.infer.expr_adjustments.get(&e)1666            && let Some(it) = it.last()1667        {1668            ty = Some(it.target.as_ref());1669        }1670        ty.unwrap_or_else(|| self.expr_ty_without_adjust(e))1671    }16721673    fn push_statement(&mut self, block: BasicBlockId, statement: Statement) {1674        self.result.basic_blocks[block].statements.push(statement);1675    }16761677    fn push_fake_read(&mut self, block: BasicBlockId, p: PlaceRef<'db>, span: MirSpan) {1678        self.push_statement(block, StatementKind::FakeRead(p.store()).with_span(span));1679    }16801681    fn push_assignment(1682        &mut self,1683        block: BasicBlockId,1684        place: PlaceRef<'db>,1685        rvalue: Rvalue,1686        span: MirSpan,1687    ) {1688        self.push_statement(block, StatementKind::Assign(place.store(), rvalue).with_span(span));1689    }16901691    fn discr_temp_place(&mut self, current: BasicBlockId) -> PlaceRef<'db> {1692        match &self.discr_temp {1693            Some(it) => it.as_ref(),1694            None => {1695                // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well1696                let discr_ty = Ty::new_int(self.interner(), rustc_type_ir::IntTy::I128);1697                let tmp: PlaceRef<'_> = self1698                    .temp(discr_ty, current, MirSpan::Unknown)1699                    .expect("discr_ty is never unsized")1700                    .into();1701                self.discr_temp = Some(tmp.store());1702                tmp1703            }1704        }1705    }17061707    fn lower_loop(1708        &mut self,1709        prev_block: BasicBlockId,1710        place: PlaceRef<'db>,1711        label: Option<LabelId>,1712        span: MirSpan,1713        f: impl FnOnce(&mut MirLowerCtx<'_, 'db>, BasicBlockId) -> Result<'db, ()>,1714    ) -> Result<'db, Option<BasicBlockId>> {1715        let begin = self.new_basic_block();1716        let prev = self.current_loop_blocks.replace(LoopBlocks {1717            begin,1718            end: None,1719            place: place.store(),1720            drop_scope_index: self.drop_scopes.len(),1721        });1722        let prev_label = if let Some(label) = label {1723            // We should generate the end now, to make sure that it wouldn't change later. It is1724            // bad as we may emit end (unnecessary unreachable block) for unterminating loop, but1725            // it should not affect correctness.1726            self.current_loop_end()?;1727            self.labeled_loop_blocks1728                .insert(label, self.current_loop_blocks.as_ref().unwrap().clone())1729        } else {1730            None1731        };1732        self.set_goto(prev_block, begin, span);1733        f(self, begin)?;1734        let my = mem::replace(&mut self.current_loop_blocks, prev).ok_or(1735            MirLowerError::ImplementationError("current_loop_blocks is corrupt".to_owned()),1736        )?;1737        if let Some(prev) = prev_label {1738            self.labeled_loop_blocks.insert(label.unwrap(), prev);1739        }1740        Ok(my.end)1741    }17421743    fn has_adjustments(&self, expr_id: ExprId) -> bool {1744        !self.infer.expr_adjustments.get(&expr_id).map(|it| it.is_empty()).unwrap_or(true)1745    }17461747    fn merge_blocks(1748        &mut self,1749        b1: Option<BasicBlockId>,1750        b2: Option<BasicBlockId>,1751        span: MirSpan,1752    ) -> Option<BasicBlockId> {1753        match (b1, b2) {1754            (None, None) => None,1755            (None, Some(b)) | (Some(b), None) => Some(b),1756            (Some(b1), Some(b2)) => {1757                let bm = self.new_basic_block();1758                self.set_goto(b1, bm, span);1759                self.set_goto(b2, bm, span);1760                Some(bm)1761            }1762        }1763    }17641765    fn current_loop_end(&mut self) -> Result<'db, BasicBlockId> {1766        let r = match self1767            .current_loop_blocks1768            .as_mut()1769            .ok_or(MirLowerError::ImplementationError(1770                "Current loop access out of loop".to_owned(),1771            ))?1772            .end1773        {1774            Some(it) => it,1775            None => {1776                let s = self.new_basic_block();1777                self.current_loop_blocks1778                    .as_mut()1779                    .ok_or(MirLowerError::ImplementationError(1780                        "Current loop access out of loop".to_owned(),1781                    ))?1782                    .end = Some(s);1783                s1784            }1785        };1786        Ok(r)1787    }17881789    fn is_uninhabited(&self, expr_id: ExprId) -> bool {1790        is_ty_uninhabited_from(1791            &self.infcx,1792            self.infer.expr_ty(expr_id),1793            self.owner.module(self.db),1794            self.env,1795        )1796    }17971798    /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and1799    /// `Drop` in the appropriated places.1800    fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<'db, ()> {1801        let l = self.binding_local(b)?;1802        self.push_storage_live_for_local(l, current, MirSpan::BindingId(b))1803    }18041805    fn push_storage_live_for_local(1806        &mut self,1807        l: LocalId,1808        current: BasicBlockId,1809        span: MirSpan,1810    ) -> Result<'db, ()> {1811        self.drop_scopes.last_mut().unwrap().locals.push(l);1812        self.push_statement(current, StatementKind::StorageLive(l).with_span(span));1813        Ok(())1814    }18151816    fn lower_block_to_place(1817        &mut self,1818        statements: &[hir_def::hir::Statement],1819        mut current: BasicBlockId,1820        tail: Option<ExprId>,1821        place: PlaceRef<'db>,1822        span: MirSpan,1823    ) -> Result<'db, Option<Idx<BasicBlock>>> {1824        let scope = self.push_drop_scope();1825        for statement in statements.iter() {1826            match statement {1827                hir_def::hir::Statement::Let { pat, initializer, else_branch, type_ref: _ } => {1828                    if let Some(expr_id) = initializer {1829                        let else_block;1830                        let Some((init_place, c)) =1831                            self.lower_expr_as_place(current, *expr_id, true)?1832                        else {1833                            scope.pop_assume_dropped(self);1834                            return Ok(None);1835                        };1836                        current = c;1837                        self.push_fake_read(current, init_place, span);1838                        // Using the initializer for the resolver scope is good enough for us, as it cannot create new declarations1839                        // and has all declarations of the `let`.1840                        let resolver_guard = self.resolver.update_to_inner_scope(1841                            self.db,1842                            self.store_owner,1843                            *expr_id,1844                        );1845                        (current, else_block) =1846                            self.pattern_match(current, None, init_place, *pat)?;1847                        self.resolver.reset_to_guard(resolver_guard);1848                        match (else_block, else_branch) {1849                            (None, _) => (),1850                            (Some(else_block), None) => {1851                                self.set_terminator(else_block, TerminatorKind::Unreachable, span);1852                            }1853                            (Some(else_block), Some(else_branch)) => {1854                                if let Some((_, b)) =1855                                    self.lower_expr_as_place(else_block, *else_branch, true)?1856                                {1857                                    self.set_terminator(b, TerminatorKind::Unreachable, span);1858                                }1859                            }1860                        }1861                    } else {1862                        let mut err = None;1863                        self.store.walk_bindings_in_pat(*pat, |b| {1864                            if let Err(e) = self.push_storage_live(b, current) {1865                                err = Some(e);1866                            }1867                        });1868                        if let Some(e) = err {1869                            return Err(e);1870                        }1871                    }1872                }1873                &hir_def::hir::Statement::Expr { expr, has_semi: _ } => {1874                    let scope2 = self.push_drop_scope();1875                    let Some((p, c)) = self.lower_expr_as_place(current, expr, true)? else {1876                        scope2.pop_assume_dropped(self);1877                        scope.pop_assume_dropped(self);1878                        return Ok(None);1879                    };1880                    self.push_fake_read(c, p, expr.into());1881                    current = scope2.pop_and_drop(self, c, expr.into());1882                }1883                hir_def::hir::Statement::Item(_) => (),1884            }1885        }1886        if let Some(tail) = tail {1887            let Some(c) = self.lower_expr_to_place(tail, place, current)? else {1888                scope.pop_assume_dropped(self);1889                return Ok(None);1890            };1891            current = c;1892        }1893        current = scope.pop_and_drop(self, current, span);1894        Ok(Some(current))1895    }18961897    fn lower_params_and_bindings(1898        &mut self,1899        params: impl Iterator<Item = (PatId, Ty<'db>)> + Clone,1900        self_binding: Option<(BindingId, Ty<'db>)>,1901        pick_binding: impl Fn(BindingId) -> bool,1902    ) -> Result<'db, BasicBlockId> {1903        let base_param_count = self.result.param_locals.len();1904        let self_binding = match self_binding {1905            Some((self_binding, ty)) => {1906                let local_id = self.result.locals.alloc(Local { ty: ty.store() });1907                self.drop_scopes.last_mut().unwrap().locals.push(local_id);1908                self.result.binding_locals.insert(self_binding, local_id);1909                self.result.param_locals.push(local_id);1910                Some(self_binding)1911            }1912            None => None,1913        };1914        self.result.param_locals.extend(params.clone().map(|(it, ty)| {1915            let local_id = self.result.locals.alloc(Local { ty: ty.store() });1916            self.drop_scopes.last_mut().unwrap().locals.push(local_id);1917            if let Pat::Bind { id, subpat: None } = self.store[it]1918                && matches!(1919                    self.store[id].mode,1920                    BindingAnnotation::Unannotated | BindingAnnotation::Mutable1921                )1922            {1923                self.result.binding_locals.insert(id, local_id);1924            }1925            local_id1926        }));1927        // and then rest of bindings1928        for (id, _) in self.store.bindings() {1929            if !pick_binding(id) {1930                continue;1931            }1932            if !self.result.binding_locals.contains_idx(id) {1933                self.result.binding_locals.insert(1934                    id,1935                    self.result.locals.alloc(Local { ty: self.infer.binding_ty(id).store() }),1936                );1937            }1938        }1939        let mut current = self.result.start_block;1940        if let Some(self_binding) = self_binding {1941            let local = self.result.param_locals.clone()[base_param_count];1942            if local != self.binding_local(self_binding)? {1943                let r = self.match_self_param(self_binding, current, local)?;1944                if let Some(b) = r.1 {1945                    self.set_terminator(b, TerminatorKind::Unreachable, MirSpan::SelfParam);1946                }1947                current = r.0;1948            }1949        }1950        let local_params = self1951            .result1952            .param_locals1953            .clone()1954            .into_iter()1955            .skip(base_param_count + self_binding.is_some() as usize);1956        for ((param, _), local) in params.zip(local_params) {1957            if let Pat::Bind { id, .. } = self.store[param]1958                && local == self.binding_local(id)?1959            {1960                continue;1961            }1962            let r = self.pattern_match(current, None, local.into(), param)?;1963            if let Some(b) = r.1 {1964                self.set_terminator(b, TerminatorKind::Unreachable, param.into());1965            }1966            current = r.0;1967        }1968        Ok(current)1969    }19701971    fn binding_local(&self, b: BindingId) -> Result<'db, LocalId> {1972        match self.result.binding_locals.get(b) {1973            Some(it) => Ok(*it),1974            None => {1975                // FIXME: It should never happens, but currently it will happen in some cases, not sure when exactly.1976                // never!("Using inaccessible local for binding is always a bug");1977                Err(MirLowerError::InaccessibleLocal)1978            }1979        }1980    }19811982    fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> {1983        let r = self.db.const_eval_discriminant(variant);1984        match r {1985            Ok(r) => Ok(r),1986            Err(e) => {1987                let edition = self.edition();1988                let db = self.db;1989                let loc = variant.lookup(db);1990                let name = format!(1991                    "{}::{}",1992                    EnumSignature::of(db, loc.parent).name.display(db, edition),1993                    loc.parent1994                        .enum_variants(self.db)1995                        .variant_name_by_id(variant)1996                        .unwrap()1997                        .display(db, edition),1998                );1999                Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))2000            }

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.