Skip to main content

hir_ty/mir/
lower.rs

1//! This module generates a polymorphic MIR from a hir body
2
3use std::{fmt::Write, iter, mem};
4
5use base_db::Crate;
6use hir_def::{
7    AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, GenericParamId, HasModule,
8    ItemContainerId, LocalFieldId, Lookup, TraitId,
9    expr_store::{Body, ExpressionStore, HygieneId, body::Param, 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 salsa::Update;
27use span::{Edition, FileId};
28use syntax::TextRange;
29
30use crate::{
31    Adjust, Adjustment, AutoBorrow, CallableDefId, InferBodyId, ParamEnvAndCrate,
32    consteval::ConstEvalError,
33    db::{GeneralConstId, HirDatabase, InternedClosure, InternedClosureId},
34    display::{DisplayTarget, HirDisplay, hir_display_with_store},
35    generics::generics,
36    infer::{
37        CaptureSourceStack, CapturedPlace, UpvarCapture,
38        cast::CastTy,
39        closure::analysis::expr_use_visitor::{
40            Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
41        },
42    },
43    inhabitedness::is_ty_uninhabited_from,
44    layout::LayoutError,
45    method_resolution::CandidateId,
46    mir::{
47        AggregateKind, Arena, BasicBlock, BasicBlockId, BinOp, BorrowKind, CastKind, Expr,
48        FieldIndex, GenericArgs, Idx, InferenceResult, Local, LocalId, MemoryMap, MirBody, MirSpan,
49        Mutability, Operand, Place, PlaceElem, PointerCast, Projection, ProjectionElem, Rvalue,
50        Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, Ty, UnOp, VariantId,
51        return_slot,
52    },
53    next_solver::{
54        Const, DbInterner, ParamConst, ParamEnv, Region, StoredGenericArgs, StoredTy, TyKind,
55        TypingMode, UnevaluatedConst,
56        abi::Safety,
57        infer::{DbInternerInferExt, InferCtxt},
58    },
59};
60
61use super::{OperandKind, PlaceRef};
62
63mod as_place;
64mod pattern_matching;
65#[cfg(test)]
66mod tests;
67
68#[derive(Debug, Clone)]
69struct LoopBlocks {
70    begin: BasicBlockId,
71    /// `None` for loops that are not terminating
72    end: Option<BasicBlockId>,
73    place: Place,
74    drop_scope_index: usize,
75}
76
77#[derive(Debug, Clone, Default)]
78struct DropScope {
79    /// locals, in order of definition (so we should run drop glues in reverse order)
80    locals: Vec<LocalId>,
81}
82
83struct MirLowerCtx<'a, 'db> {
84    result: MirBody<'db>,
85    owner: InferBodyId<'db>,
86    store_owner: ExpressionStoreOwnerId,
87    current_loop_blocks: Option<LoopBlocks>,
88    labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>,
89    discr_temp: Option<Place>,
90    db: &'db dyn HirDatabase,
91    store: &'a ExpressionStore,
92    infer: &'a InferenceResult<'db>,
93    types: &'db crate::next_solver::DefaultAny<'db>,
94    resolver: Resolver<'db>,
95    drop_scopes: Vec<DropScope>,
96    env: ParamEnv<'db>,
97    infcx: InferCtxt<'db>,
98}
99
100// FIXME: Make this smaller, its stored in database queries
101#[derive(Debug, Clone, PartialEq, Eq, Update)]
102pub enum MirLowerError<'db> {
103    ConstEvalError(Box<str>, Box<ConstEvalError<'db>>),
104    LayoutError(LayoutError),
105    IncompleteExpr,
106    IncompletePattern,
107    /// Trying to lower a trait function, instead of an implementation
108    TraitFunctionDefinition(TraitId, Name),
109    UnresolvedName(String),
110    RecordLiteralWithoutPath,
111    UnresolvedMethod(String),
112    UnresolvedField,
113    UnsizedTemporary(StoredTy),
114    MissingFunctionDefinition(InferBodyId<'db>, ExprId),
115    HasErrors,
116    /// This should never happen. Type mismatch should catch everything.
117    TypeError(&'static str),
118    NotSupported(String),
119    ContinueWithoutLoop,
120    BreakWithoutLoop,
121    Loop,
122    /// Something that should never happen and is definitely a bug, but we don't want to panic if it happened
123    ImplementationError(String),
124    LangItemNotFound,
125    MutatingRvalue,
126    UnresolvedLabel,
127    UnresolvedUpvar(Place),
128    InaccessibleLocal,
129
130    // monomorphization errors:
131    GenericArgNotProvided(GenericParamId, StoredGenericArgs),
132}
133
134/// A token to ensuring that each drop scope is popped at most once, thanks to the compiler that checks moves.
135struct DropScopeToken;
136impl DropScopeToken {
137    fn pop_and_drop<'db>(
138        self,
139        ctx: &mut MirLowerCtx<'_, 'db>,
140        current: BasicBlockId,
141        span: MirSpan,
142    ) -> BasicBlockId {
143        std::mem::forget(self);
144        ctx.pop_drop_scope_internal(current, span)
145    }
146
147    /// It is useful when we want a drop scope is syntactically closed, but we don't want to execute any drop
148    /// code. Either when the control flow is diverging (so drop code doesn't reached) or when drop is handled
149    /// for us (for example a block that ended with a return statement. Return will drop everything, so the block shouldn't
150    /// do anything)
151    fn pop_assume_dropped(self, ctx: &mut MirLowerCtx<'_, '_>) {
152        std::mem::forget(self);
153        ctx.pop_drop_scope_assume_dropped_internal();
154    }
155}
156
157impl Drop for DropScopeToken {
158    fn drop(&mut self) {}
159}
160
161// Uncomment this to make `DropScopeToken` a drop bomb. Unfortunately we can't do this in release, since
162// in cases that mir lowering fails, we don't handle (and don't need to handle) drop scopes so it will be
163// actually reached. `pop_drop_scope_assert_finished` will also detect this case, but doesn't show useful
164// stack trace.
165//
166// impl Drop for DropScopeToken {
167//     fn drop(&mut self) {
168//         never!("Drop scope doesn't popped");
169//     }
170// }
171
172impl MirLowerError<'_> {
173    pub fn pretty_print(
174        &self,
175        f: &mut String,
176        db: &dyn HirDatabase,
177        span_formatter: impl Fn(FileId, TextRange) -> String,
178        display_target: DisplayTarget,
179    ) -> std::result::Result<(), std::fmt::Error> {
180        match self {
181            MirLowerError::ConstEvalError(name, e) => {
182                writeln!(f, "In evaluating constant {name}")?;
183                match &**e {
184                    ConstEvalError::MirLowerError(e) => {
185                        e.pretty_print(f, db, span_formatter, display_target)?
186                    }
187                    ConstEvalError::MirEvalError(e) => {
188                        e.pretty_print(f, db, span_formatter, display_target)?
189                    }
190                }
191            }
192            MirLowerError::MissingFunctionDefinition(owner, it) => {
193                let owner = owner.expression_store_owner(db);
194                let store = ExpressionStore::of(db, owner);
195                writeln!(
196                    f,
197                    "Missing function definition for {}",
198                    hir_def::expr_store::pretty::print_expr_hir(
199                        db,
200                        store,
201                        owner,
202                        *it,
203                        display_target.edition
204                    )
205                )?;
206            }
207            MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,
208            MirLowerError::GenericArgNotProvided(id, subst) => {
209                let param_name = match *id {
210                    GenericParamId::TypeParamId(id) => {
211                        GenericParams::of(db, id.parent())[id.local_id()].name().cloned()
212                    }
213                    GenericParamId::ConstParamId(id) => {
214                        GenericParams::of(db, id.parent())[id.local_id()].name().cloned()
215                    }
216                    GenericParamId::LifetimeParamId(id) => {
217                        Some(GenericParams::of(db, id.parent)[id.local_id].name.clone())
218                    }
219                };
220                writeln!(
221                    f,
222                    "Generic arg not provided for {}",
223                    param_name.unwrap_or(Name::missing()).display(db, display_target.edition)
224                )?;
225                writeln!(f, "Provided args: [")?;
226                for g in subst.as_ref() {
227                    write!(f, "    {},", g.display(db, display_target))?;
228                }
229                writeln!(f, "]")?;
230            }
231            MirLowerError::LayoutError(_)
232            | MirLowerError::UnsizedTemporary(_)
233            | MirLowerError::IncompleteExpr
234            | MirLowerError::IncompletePattern
235            | MirLowerError::InaccessibleLocal
236            | MirLowerError::TraitFunctionDefinition(_, _)
237            | MirLowerError::UnresolvedName(_)
238            | MirLowerError::RecordLiteralWithoutPath
239            | MirLowerError::UnresolvedMethod(_)
240            | MirLowerError::UnresolvedField
241            | MirLowerError::TypeError(_)
242            | MirLowerError::NotSupported(_)
243            | MirLowerError::ContinueWithoutLoop
244            | MirLowerError::BreakWithoutLoop
245            | MirLowerError::Loop
246            | MirLowerError::ImplementationError(_)
247            | MirLowerError::LangItemNotFound
248            | MirLowerError::MutatingRvalue
249            | MirLowerError::UnresolvedLabel
250            | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?,
251        }
252        Ok(())
253    }
254}
255
256macro_rules! not_supported {
257    ($it: expr) => {
258        return Err(MirLowerError::NotSupported(format!($it)))
259    };
260}
261
262macro_rules! implementation_error {
263    ($it: expr) => {{
264        ::stdx::never!("MIR lower implementation bug: {}", format!($it));
265        return Err(MirLowerError::ImplementationError(format!($it)));
266    }};
267}
268
269impl From<LayoutError> for MirLowerError<'_> {
270    fn from(value: LayoutError) -> Self {
271        MirLowerError::LayoutError(value)
272    }
273}
274
275impl MirLowerError<'_> {
276    fn unresolved_path(
277        db: &dyn HirDatabase,
278        p: &Path,
279        display_target: DisplayTarget,
280        owner: ExpressionStoreOwnerId,
281        store: &ExpressionStore,
282    ) -> Self {
283        Self::UnresolvedName(
284            hir_display_with_store(p, owner, store).display(db, display_target).to_string(),
285        )
286    }
287}
288
289type Result<'db, T> = std::result::Result<T, MirLowerError<'db>>;
290
291impl<'a, 'db> MirLowerCtx<'a, 'db> {
292    fn new(
293        db: &'db dyn HirDatabase,
294        owner: InferBodyId<'db>,
295        store: &'a ExpressionStore,
296        infer: &'a InferenceResult<'db>,
297    ) -> Self {
298        let mut basic_blocks = Arena::new();
299        let start_block = basic_blocks.alloc(BasicBlock {
300            statements: vec![],
301            terminator: None,
302            is_cleanup: false,
303        });
304        let locals = Arena::new();
305        let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new();
306        let mir = MirBody {
307            basic_blocks,
308            locals,
309            start_block,
310            binding_locals,
311            upvar_locals: FxHashMap::default(),
312            param_locals: vec![],
313            owner,
314            closures: vec![],
315        };
316        let store_owner = owner.expression_store_owner(db);
317        let resolver = owner.resolver(db);
318        let env = db.trait_environment(owner.generic_def(db));
319        let interner = DbInterner::new_with(db, resolver.krate());
320        // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body?
321        let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
322
323        MirLowerCtx {
324            result: mir,
325            db,
326            infer,
327            store,
328            types: crate::next_solver::default_types(db),
329            owner,
330            store_owner,
331            resolver,
332            current_loop_blocks: None,
333            labeled_loop_blocks: Default::default(),
334            discr_temp: None,
335            drop_scopes: vec![DropScope::default()],
336            env,
337            infcx,
338        }
339    }
340
341    #[inline]
342    fn interner(&self) -> DbInterner<'db> {
343        self.infcx.interner
344    }
345
346    #[inline]
347    fn lang_items(&self) -> &'db LangItems {
348        self.infcx.interner.lang_items()
349    }
350
351    fn temp(&mut self, ty: Ty<'db>, current: BasicBlockId, span: MirSpan) -> Result<'db, LocalId> {
352        if matches!(ty.kind(), TyKind::Slice(_) | TyKind::Dynamic(..)) {
353            return Err(MirLowerError::UnsizedTemporary(ty.store()));
354        }
355        let l = self.result.locals.alloc(Local { ty: ty.store() });
356        self.push_storage_live_for_local(l, current, span)?;
357        Ok(l)
358    }
359
360    fn lower_expr_to_some_operand(
361        &mut self,
362        expr_id: ExprId,
363        current: BasicBlockId,
364    ) -> Result<'db, Option<(Operand, BasicBlockId)>> {
365        if !self.has_adjustments(expr_id)
366            && let Expr::Literal(l) = &self.store[expr_id]
367        {
368            let ty = self.expr_ty_without_adjust(expr_id);
369            return Ok(Some((self.lower_literal_to_operand(ty, l)?, current)));
370        }
371        let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else {
372            return Ok(None);
373        };
374        Ok(Some((
375            Operand { kind: OperandKind::Copy(p.store()), span: Some(expr_id.into()) },
376            current,
377        )))
378    }
379
380    fn lower_expr_to_place_with_adjust(
381        &mut self,
382        expr_id: ExprId,
383        place: PlaceRef<'db>,
384        current: BasicBlockId,
385        adjustments: &[Adjustment],
386    ) -> Result<'db, Option<BasicBlockId>> {
387        match adjustments.split_last() {
388            Some((last, rest)) => match &last.kind {
389                Adjust::NeverToAny => {
390                    let temp = self.temp(self.types.types.never, current, MirSpan::Unknown)?;
391                    self.lower_expr_to_place_with_adjust(expr_id, temp.into(), current, rest)
392                }
393                Adjust::Deref(_) => {
394                    let Some((p, current)) =
395                        self.lower_expr_as_place_with_adjust(current, expr_id, true, adjustments)?
396                    else {
397                        return Ok(None);
398                    };
399                    self.push_assignment(
400                        current,
401                        place,
402                        Operand { kind: OperandKind::Copy(p.store()), span: None }.into(),
403                        expr_id.into(),
404                    );
405                    Ok(Some(current))
406                }
407                Adjust::Borrow(AutoBorrow::Ref(m)) => self.lower_expr_to_place_with_borrow_adjust(
408                    expr_id,
409                    place,
410                    current,
411                    rest,
412                    (*m).into(),
413                ),
414                Adjust::Borrow(AutoBorrow::RawPtr(m)) => {
415                    self.lower_expr_to_place_with_borrow_adjust(expr_id, place, current, rest, *m)
416                }
417                Adjust::Pointer(cast) => {
418                    let Some((p, current)) =
419                        self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)?
420                    else {
421                        return Ok(None);
422                    };
423                    self.push_assignment(
424                        current,
425                        place,
426                        Rvalue::Cast(
427                            CastKind::PointerCoercion(*cast),
428                            Operand { kind: OperandKind::Copy(p.store()), span: None },
429                            last.target.clone(),
430                        ),
431                        expr_id.into(),
432                    );
433                    Ok(Some(current))
434                }
435            },
436            None => self.lower_expr_to_place_without_adjust(expr_id, place, current),
437        }
438    }
439
440    fn lower_expr_to_place_with_borrow_adjust(
441        &mut self,
442        expr_id: ExprId,
443        place: PlaceRef<'db>,
444        current: BasicBlockId,
445        rest: &[Adjustment],
446        m: Mutability,
447    ) -> Result<'db, Option<BasicBlockId>> {
448        let Some((p, current)) =
449            self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)?
450        else {
451            return Ok(None);
452        };
453        let bk = BorrowKind::from_rustc_mutability(m);
454        self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into());
455        Ok(Some(current))
456    }
457
458    fn lower_expr_to_place(
459        &mut self,
460        expr_id: ExprId,
461        place: PlaceRef<'db>,
462        prev_block: BasicBlockId,
463    ) -> Result<'db, Option<BasicBlockId>> {
464        if let Some(adjustments) = self.infer.expr_adjustments.get(&expr_id) {
465            return self.lower_expr_to_place_with_adjust(expr_id, place, prev_block, adjustments);
466        }
467        self.lower_expr_to_place_without_adjust(expr_id, place, prev_block)
468    }
469
470    fn lower_expr_to_place_without_adjust(
471        &mut self,
472        expr_id: ExprId,
473        place: PlaceRef<'db>,
474        mut current: BasicBlockId,
475    ) -> Result<'db, Option<BasicBlockId>> {
476        match &self.store[expr_id] {
477            Expr::OffsetOf(_) => {
478                not_supported!("builtin#offset_of")
479            }
480            Expr::InlineAsm(_) => {
481                not_supported!("builtin#asm")
482            }
483            Expr::Missing => {
484                if let Some(f) = self.owner.as_function() {
485                    let assoc = f.lookup(self.db);
486                    if let ItemContainerId::TraitId(t) = assoc.container {
487                        let name = &FunctionSignature::of(self.db, f).name;
488                        return Err(MirLowerError::TraitFunctionDefinition(t, name.clone()));
489                    }
490                }
491                Err(MirLowerError::IncompleteExpr)
492            }
493            Expr::Path(p) => {
494                let pr =
495                    if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) {
496                        match assoc {
497                            CandidateId::ConstId(c) => {
498                                self.lower_const(c.into(), current, place, subst, expr_id.into())?;
499                                return Ok(Some(current));
500                            }
501                            CandidateId::FunctionId(_) => {
502                                // FnDefs are zero sized, no action is needed.
503                                return Ok(Some(current));
504                            }
505                        }
506                    } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {
507                        match variant {
508                            VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),
509                            VariantId::StructId(s) => ValueNs::StructId(s),
510                            VariantId::UnionId(_) => implementation_error!("Union variant as path"),
511                        }
512                    } else {
513                        let resolver_guard =
514                            self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);
515                        let hygiene = self.store.expr_path_hygiene(expr_id);
516                        let result = self
517                            .resolver
518                            .resolve_path_in_value_ns_fully(self.db, p, hygiene)
519                            .ok_or_else(|| {
520                                MirLowerError::unresolved_path(
521                                    self.db,
522                                    p,
523                                    DisplayTarget::from_crate(self.db, self.krate()),
524                                    self.owner.expression_store_owner(self.db),
525                                    self.store,
526                                )
527                            })?;
528                        self.resolver.reset_to_guard(resolver_guard);
529                        result
530                    };
531                match pr {
532                    ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => {
533                        let Some((temp, current)) =
534                            self.lower_expr_as_place_without_adjust(current, expr_id, false)?
535                        else {
536                            return Ok(None);
537                        };
538                        self.push_assignment(
539                            current,
540                            place,
541                            Operand { kind: OperandKind::Copy(temp.store()), span: None }.into(),
542                            expr_id.into(),
543                        );
544                        Ok(Some(current))
545                    }
546                    ValueNs::ConstId(const_id) => {
547                        self.lower_const(
548                            const_id.into(),
549                            current,
550                            place,
551                            GenericArgs::empty(self.interner()),
552                            expr_id.into(),
553                        )?;
554                        Ok(Some(current))
555                    }
556                    ValueNs::EnumVariantId(variant_id) => {
557                        let variant_fields = variant_id.fields(self.db);
558                        if variant_fields.shape == FieldsShape::Unit {
559                            let ty = self.infer.expr_ty(expr_id);
560                            current = self.lower_enum_variant(
561                                variant_id,
562                                current,
563                                place,
564                                ty,
565                                Box::new([]),
566                                expr_id.into(),
567                            )?;
568                        }
569                        // Otherwise its a tuple like enum, treated like a zero sized function, so no action is needed
570                        Ok(Some(current))
571                    }
572                    ValueNs::GenericParam(p) => {
573                        let def = self.owner.generic_def(self.db);
574                        let generics = generics(self.db, def);
575                        let index = generics.type_or_const_param_idx(p.into());
576                        self.push_assignment(
577                            current,
578                            place,
579                            Rvalue::from(Operand {
580                                kind: OperandKind::Constant {
581                                    konst: Const::new_param(
582                                        self.interner(),
583                                        ParamConst { id: p, index },
584                                    )
585                                    .store(),
586                                    ty: self.db.const_param_ty(p).store(),
587                                },
588                                span: None,
589                            }),
590                            expr_id.into(),
591                        );
592                        Ok(Some(current))
593                    }
594                    ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::ImplSelf(_) => {
595                        // It's probably a unit struct or a zero sized function, so no action is needed.
596                        Ok(Some(current))
597                    }
598                }
599            }
600            Expr::If { condition, then_branch, else_branch } => {
601                let Some((discr, current)) =
602                    self.lower_expr_to_some_operand(*condition, current)?
603                else {
604                    return Ok(None);
605                };
606                let start_of_then = self.new_basic_block();
607                let end_of_then = self.lower_expr_to_place(*then_branch, place, start_of_then)?;
608                let start_of_else = self.new_basic_block();
609                let end_of_else = if let Some(else_branch) = else_branch {
610                    self.lower_expr_to_place(*else_branch, place, start_of_else)?
611                } else {
612                    Some(start_of_else)
613                };
614                self.set_terminator(
615                    current,
616                    TerminatorKind::SwitchInt {
617                        discr,
618                        targets: SwitchTargets::static_if(1, start_of_then, start_of_else),
619                    },
620                    expr_id.into(),
621                );
622                Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into()))
623            }
624            Expr::Let { pat, expr } => {
625                let Some((cond_place, current)) = self.lower_expr_as_place(current, *expr, true)?
626                else {
627                    return Ok(None);
628                };
629                self.push_fake_read(current, cond_place, expr_id.into());
630                let resolver_guard =
631                    self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);
632                let (then_target, else_target) =
633                    self.pattern_match(current, None, cond_place, *pat)?;
634                self.resolver.reset_to_guard(resolver_guard);
635                self.write_bytes_to_place(
636                    then_target,
637                    place,
638                    Box::new([1]),
639                    Ty::new_bool(self.interner()),
640                    MirSpan::Unknown,
641                )?;
642                if let Some(else_target) = else_target {
643                    self.write_bytes_to_place(
644                        else_target,
645                        place,
646                        Box::new([0]),
647                        Ty::new_bool(self.interner()),
648                        MirSpan::Unknown,
649                    )?;
650                }
651                Ok(self.merge_blocks(Some(then_target), else_target, expr_id.into()))
652            }
653            Expr::Unsafe { id: _, statements, tail } => {
654                self.lower_block_to_place(statements, current, *tail, place, expr_id.into())
655            }
656            Expr::Block { id: _, statements, tail, label } => {
657                if let Some(label) = label {
658                    self.lower_loop(current, place, Some(*label), expr_id.into(), |this, begin| {
659                        if let Some(current) = this.lower_block_to_place(
660                            statements,
661                            begin,
662                            *tail,
663                            place,
664                            expr_id.into(),
665                        )? {
666                            let end = this.current_loop_end()?;
667                            this.set_goto(current, end, expr_id.into());
668                        }
669                        Ok(())
670                    })
671                } else {
672                    self.lower_block_to_place(statements, current, *tail, place, expr_id.into())
673                }
674            }
675            Expr::Loop { body, label, source: _ } => {
676                self.lower_loop(current, place, *label, expr_id.into(), |this, begin| {
677                    let scope = this.push_drop_scope();
678                    if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? {
679                        current = scope.pop_and_drop(this, current, body.into());
680                        this.set_goto(current, begin, expr_id.into());
681                    } else {
682                        scope.pop_assume_dropped(this);
683                    }
684                    Ok(())
685                })
686            }
687            Expr::Call { callee, args, .. } => {
688                if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {
689                    let ty = Ty::new_fn_def(
690                        self.interner(),
691                        CallableDefId::FunctionId(func_id).into(),
692                        generic_args,
693                    );
694                    let func = Operand::from_bytes(Box::default(), ty);
695                    return self.lower_call_and_args(
696                        func,
697                        iter::once(*callee).chain(args.iter().copied()),
698                        place,
699                        current,
700                        self.is_uninhabited(expr_id),
701                        expr_id.into(),
702                    );
703                }
704                let callee_ty = self.expr_ty_after_adjustments(*callee);
705                match callee_ty.kind() {
706                    TyKind::FnDef(..) => {
707                        let func = Operand::from_bytes(Box::default(), callee_ty);
708                        self.lower_call_and_args(
709                            func,
710                            args.iter().copied(),
711                            place,
712                            current,
713                            self.is_uninhabited(expr_id),
714                            expr_id.into(),
715                        )
716                    }
717                    TyKind::FnPtr(..) => {
718                        let Some((func, current)) =
719                            self.lower_expr_to_some_operand(*callee, current)?
720                        else {
721                            return Ok(None);
722                        };
723                        self.lower_call_and_args(
724                            func,
725                            args.iter().copied(),
726                            place,
727                            current,
728                            self.is_uninhabited(expr_id),
729                            expr_id.into(),
730                        )
731                    }
732                    TyKind::Closure(_, _) => {
733                        not_supported!(
734                            "method resolution not emitted for closure (Are Fn traits available?)"
735                        );
736                    }
737                    TyKind::Error(_) => {
738                        Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id))
739                    }
740                    _ => Err(MirLowerError::TypeError("function call on bad type")),
741                }
742            }
743            Expr::MethodCall { receiver, args, method_name, .. } => {
744                let (func_id, generic_args) =
745                    self.infer.method_resolution(expr_id).ok_or_else(|| {
746                        MirLowerError::UnresolvedMethod(
747                            method_name.display(self.db, self.edition()).to_string(),
748                        )
749                    })?;
750                let func = Operand::from_fn(self.db, func_id, generic_args);
751                self.lower_call_and_args(
752                    func,
753                    iter::once(*receiver).chain(args.iter().copied()),
754                    place,
755                    current,
756                    self.is_uninhabited(expr_id),
757                    expr_id.into(),
758                )
759            }
760            Expr::Match { expr, arms } => {
761                let Some((cond_place, mut current)) =
762                    self.lower_expr_as_place(current, *expr, true)?
763                else {
764                    return Ok(None);
765                };
766                self.push_fake_read(current, cond_place, expr_id.into());
767                let mut end = None;
768                let resolver_guard =
769                    self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);
770                for MatchArm { pat, guard, expr } in arms.iter() {
771                    let (then, mut otherwise) =
772                        self.pattern_match(current, None, cond_place, *pat)?;
773                    let then = if let &Some(guard) = guard {
774                        let next = self.new_basic_block();
775                        let o = otherwise.get_or_insert_with(|| self.new_basic_block());
776                        if let Some((discr, c)) = self.lower_expr_to_some_operand(guard, then)? {
777                            self.set_terminator(
778                                c,
779                                TerminatorKind::SwitchInt {
780                                    discr,
781                                    targets: SwitchTargets::static_if(1, next, *o),
782                                },
783                                expr_id.into(),
784                            );
785                        }
786                        next
787                    } else {
788                        then
789                    };
790                    if let Some(block) = self.lower_expr_to_place(*expr, place, then)? {
791                        let r = end.get_or_insert_with(|| self.new_basic_block());
792                        self.set_goto(block, *r, expr_id.into());
793                    }
794                    match otherwise {
795                        Some(o) => current = o,
796                        None => {
797                            // The current pattern was irrefutable, so there is no need to generate code
798                            // for the rest of patterns
799                            break;
800                        }
801                    }
802                }
803                self.resolver.reset_to_guard(resolver_guard);
804                if self.is_unterminated(current) {
805                    self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into());
806                }
807                Ok(end)
808            }
809            Expr::Continue { label } => {
810                let loop_data = match label {
811                    Some(l) => {
812                        self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?
813                    }
814                    None => self
815                        .current_loop_blocks
816                        .as_ref()
817                        .ok_or(MirLowerError::ContinueWithoutLoop)?,
818                };
819                let begin = loop_data.begin;
820                current =
821                    self.drop_until_scope(loop_data.drop_scope_index, current, expr_id.into());
822                self.set_goto(current, begin, expr_id.into());
823                Ok(None)
824            }
825            &Expr::Break { expr, label } => {
826                if let Some(expr) = expr {
827                    let loop_data = match label {
828                        Some(l) => self
829                            .labeled_loop_blocks
830                            .get(&l)
831                            .ok_or(MirLowerError::UnresolvedLabel)?,
832                        None => self
833                            .current_loop_blocks
834                            .as_ref()
835                            .ok_or(MirLowerError::BreakWithoutLoop)?,
836                    };
837                    let Some(c) =
838                        self.lower_expr_to_place(expr, loop_data.place.as_ref(), current)?
839                    else {
840                        return Ok(None);
841                    };
842                    current = c;
843                }
844                let (end, drop_scope) = match label {
845                    Some(l) => {
846                        let loop_blocks = self
847                            .labeled_loop_blocks
848                            .get(&l)
849                            .ok_or(MirLowerError::UnresolvedLabel)?;
850                        (
851                            loop_blocks.end.expect("We always generate end for labeled loops"),
852                            loop_blocks.drop_scope_index,
853                        )
854                    }
855                    None => (
856                        self.current_loop_end()?,
857                        self.current_loop_blocks.as_ref().unwrap().drop_scope_index,
858                    ),
859                };
860                current = self.drop_until_scope(drop_scope, current, expr_id.into());
861                self.set_goto(current, end, expr_id.into());
862                Ok(None)
863            }
864            Expr::Return { expr } => {
865                if let Some(expr) = expr {
866                    if let Some(c) =
867                        self.lower_expr_to_place(*expr, return_slot().into(), current)?
868                    {
869                        current = c;
870                    } else {
871                        return Ok(None);
872                    }
873                }
874                current = self.drop_until_scope(0, current, expr_id.into());
875                self.set_terminator(current, TerminatorKind::Return, expr_id.into());
876                Ok(None)
877            }
878            Expr::Become { .. } => not_supported!("tail-calls"),
879            Expr::Yield { .. } => not_supported!("yield"),
880            Expr::RecordLit { fields, path, spread, .. } => {
881                let spread_place = match *spread {
882                    RecordSpread::Expr(it) => {
883                        let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else {
884                            return Ok(None);
885                        };
886                        current = c;
887                        Some(p)
888                    }
889                    RecordSpread::None => None,
890                    RecordSpread::FieldDefaults => not_supported!("empty record spread"),
891                };
892                let variant_id =
893                    self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| {
894                        MirLowerError::unresolved_path(
895                            self.db,
896                            path,
897                            self.display_target(),
898                            self.owner.expression_store_owner(self.db),
899                            self.store,
900                        )
901                    })?;
902                let subst = match self.expr_ty_without_adjust(expr_id).kind() {
903                    TyKind::Adt(_, s) => s,
904                    _ => not_supported!("Non ADT record literal"),
905                };
906                let variant_fields = variant_id.fields(self.db);
907                match variant_id {
908                    VariantId::EnumVariantId(_) | VariantId::StructId(_) => {
909                        let mut operands = vec![None; variant_fields.fields().len()];
910                        for RecordLitField { name, expr } in fields.iter() {
911                            let field_id =
912                                variant_fields.field(name).ok_or(MirLowerError::UnresolvedField)?;
913                            let Some((op, c)) = self.lower_expr_to_some_operand(*expr, current)?
914                            else {
915                                return Ok(None);
916                            };
917                            current = c;
918                            operands[u32::from(field_id.into_raw()) as usize] = Some(op);
919                        }
920                        let rvalue = Rvalue::Aggregate(
921                            AggregateKind::Adt(variant_id, subst.store()),
922                            match spread_place {
923                                Some(sp) if let VariantId::StructId(_) = variant_id => operands
924                                    .into_iter()
925                                    .enumerate()
926                                    .map(|(i, it)| match it {
927                                        Some(it) => it,
928                                        None => {
929                                            let p = sp.project(ProjectionElem::Field(FieldIndex(
930                                                i as u32,
931                                            )));
932                                            Operand {
933                                                kind: OperandKind::Copy(p.store()),
934                                                span: None,
935                                            }
936                                        }
937                                    })
938                                    .collect(),
939                                Some(_) => {
940                                    return Err(MirLowerError::TypeError(
941                                        "functional record update syntax requires a struct",
942                                    ));
943                                }
944                                None => operands.into_iter().collect::<Option<_>>().ok_or(
945                                    MirLowerError::TypeError("missing field in record literal"),
946                                )?,
947                            },
948                        );
949                        self.push_assignment(current, place, rvalue, expr_id.into());
950                        Ok(Some(current))
951                    }
952                    VariantId::UnionId(_union_id) => {
953                        let [RecordLitField { name, expr }] = fields.as_ref() else {
954                            not_supported!("Union record literal with more than one field");
955                        };
956                        let local_id =
957                            variant_fields.field(name).ok_or(MirLowerError::UnresolvedField)?;
958                        let place = place.project(PlaceElem::Field(local_id.into()));
959                        self.lower_expr_to_place(*expr, place, current)
960                    }
961                }
962            }
963            Expr::Await { .. } => not_supported!("await"),
964            Expr::Yeet { .. } => not_supported!("yeet"),
965            &Expr::Const(id) => {
966                // Inline const blocks (`const { .. }`) are stored with their inner expression in
967                // the same body (see inference, which infers the inner expression directly), so we
968                // lower that expression in place. Const-ness is irrelevant here: MIR evaluation
969                // already runs in a const context.
970                self.lower_expr_to_place(id, place, current)
971            }
972            Expr::Cast { expr, type_ref: _ } => {
973                let Some((it, current)) = self.lower_expr_to_some_operand(*expr, current)? else {
974                    return Ok(None);
975                };
976                // 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)
977                // 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)
978                let rvalue = if self.infer.coercion_casts.contains(expr) {
979                    Rvalue::Use(it)
980                } else {
981                    let source_ty = self.infer.expr_ty(*expr);
982                    let target_ty = self.infer.expr_ty(expr_id);
983                    let cast_kind = if source_ty.as_reference().is_some() {
984                        CastKind::PointerCoercion(PointerCast::ArrayToPointer)
985                    } else {
986                        cast_kind(self.db, source_ty, target_ty)?
987                    };
988
989                    Rvalue::Cast(cast_kind, it, target_ty.store())
990                };
991                self.push_assignment(current, place, rvalue, expr_id.into());
992                Ok(Some(current))
993            }
994            Expr::Ref { expr, rawness: _, mutability } => {
995                let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? else {
996                    return Ok(None);
997                };
998                let bk = BorrowKind::from_hir_mutability(*mutability);
999                self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into());
1000                Ok(Some(current))
1001            }
1002            Expr::Box { expr } => {
1003                let ty = self.expr_ty_after_adjustments(*expr);
1004                self.push_assignment(
1005                    current,
1006                    place,
1007                    Rvalue::ShallowInitBoxWithAlloc(ty.store()),
1008                    expr_id.into(),
1009                );
1010                let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)?
1011                else {
1012                    return Ok(None);
1013                };
1014                let p = place.project(ProjectionElem::Deref);
1015                self.push_assignment(current, p, operand.into(), expr_id.into());
1016                Ok(Some(current))
1017            }
1018            Expr::Field { .. }
1019            | Expr::Index { .. }
1020            | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => {
1021                let Some((p, current)) =
1022                    self.lower_expr_as_place_without_adjust(current, expr_id, true)?
1023                else {
1024                    return Ok(None);
1025                };
1026                self.push_assignment(
1027                    current,
1028                    place,
1029                    Operand { kind: OperandKind::Copy(p.store()), span: None }.into(),
1030                    expr_id.into(),
1031                );
1032                Ok(Some(current))
1033            }
1034            Expr::UnaryOp {
1035                expr,
1036                op: op @ (hir_def::hir::UnaryOp::Not | hir_def::hir::UnaryOp::Neg),
1037            } => {
1038                let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)?
1039                else {
1040                    return Ok(None);
1041                };
1042                let operation = match op {
1043                    hir_def::hir::UnaryOp::Not => UnOp::Not,
1044                    hir_def::hir::UnaryOp::Neg => UnOp::Neg,
1045                    _ => unreachable!(),
1046                };
1047                self.push_assignment(
1048                    current,
1049                    place,
1050                    Rvalue::UnaryOp(operation, operand),
1051                    expr_id.into(),
1052                );
1053                Ok(Some(current))
1054            }
1055            Expr::BinaryOp { lhs, rhs, op } => {
1056                let op: BinaryOp = op.ok_or(MirLowerError::IncompleteExpr)?;
1057                let is_builtin = 'b: {
1058                    // Without adjust here is a hack. We assume that we know every possible adjustment
1059                    // for binary operator, and use without adjust to simplify our conditions.
1060                    let lhs_ty = self.expr_ty_without_adjust(*lhs);
1061                    let rhs_ty = self.expr_ty_without_adjust(*rhs);
1062                    if matches!(op, BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. }))
1063                        && matches!(lhs_ty.kind(), TyKind::RawPtr(..))
1064                        && matches!(rhs_ty.kind(), TyKind::RawPtr(..))
1065                    {
1066                        break 'b true;
1067                    }
1068                    let builtin_inequal_impls = matches!(
1069                        op,
1070                        BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr)
1071                            | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) }
1072                    );
1073                    matches!(
1074                        lhs_ty.kind(),
1075                        TyKind::Bool
1076                            | TyKind::Char
1077                            | TyKind::Int(_)
1078                            | TyKind::Uint(_)
1079                            | TyKind::Float(_)
1080                    ) && matches!(
1081                        rhs_ty.kind(),
1082                        TyKind::Bool
1083                            | TyKind::Char
1084                            | TyKind::Int(_)
1085                            | TyKind::Uint(_)
1086                            | TyKind::Float(_)
1087                    ) && (lhs_ty == rhs_ty || builtin_inequal_impls)
1088                };
1089                if !is_builtin
1090                    && let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id)
1091                {
1092                    let func = Operand::from_fn(self.db, func_id, generic_args);
1093                    return self.lower_call_and_args(
1094                        func,
1095                        [*lhs, *rhs].into_iter(),
1096                        place,
1097                        current,
1098                        self.is_uninhabited(expr_id),
1099                        expr_id.into(),
1100                    );
1101                }
1102                if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op {
1103                    // last adjustment is `&mut` which we don't want it.
1104                    let adjusts = self
1105                        .infer
1106                        .expr_adjustments
1107                        .get(lhs)
1108                        .and_then(|it| it.split_last())
1109                        .map(|it| it.1)
1110                        .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?;
1111                    let Some((lhs_place, current)) =
1112                        self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?
1113                    else {
1114                        return Ok(None);
1115                    };
1116                    let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)?
1117                    else {
1118                        return Ok(None);
1119                    };
1120                    let r_value = Rvalue::CheckedBinaryOp(
1121                        op.into(),
1122                        Operand { kind: OperandKind::Copy(lhs_place.store()), span: None },
1123                        rhs_op,
1124                    );
1125                    self.push_assignment(current, lhs_place, r_value, expr_id.into());
1126                    return Ok(Some(current));
1127                }
1128                let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)?
1129                else {
1130                    return Ok(None);
1131                };
1132                if let hir_def::hir::BinaryOp::LogicOp(op) = op {
1133                    let value_to_short = match op {
1134                        syntax::ast::LogicOp::And => 0,
1135                        syntax::ast::LogicOp::Or => 1,
1136                    };
1137                    let start_of_then = self.new_basic_block();
1138                    self.push_assignment(
1139                        start_of_then,
1140                        place,
1141                        lhs_op.clone().into(),
1142                        expr_id.into(),
1143                    );
1144                    let end_of_then = Some(start_of_then);
1145                    let start_of_else = self.new_basic_block();
1146                    let end_of_else = self.lower_expr_to_place(*rhs, place, start_of_else)?;
1147                    self.set_terminator(
1148                        current,
1149                        TerminatorKind::SwitchInt {
1150                            discr: lhs_op,
1151                            targets: SwitchTargets::static_if(
1152                                value_to_short,
1153                                start_of_then,
1154                                start_of_else,
1155                            ),
1156                        },
1157                        expr_id.into(),
1158                    );
1159                    return Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into()));
1160                }
1161                let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)?
1162                else {
1163                    return Ok(None);
1164                };
1165                self.push_assignment(
1166                    current,
1167                    place,
1168                    Rvalue::CheckedBinaryOp(
1169                        match op {
1170                            hir_def::hir::BinaryOp::LogicOp(op) => match op {
1171                                hir_def::hir::LogicOp::And => BinOp::BitAnd, // FIXME: make these short circuit
1172                                hir_def::hir::LogicOp::Or => BinOp::BitOr,
1173                            },
1174                            hir_def::hir::BinaryOp::ArithOp(op) => BinOp::from(op),
1175                            hir_def::hir::BinaryOp::CmpOp(op) => BinOp::from(op),
1176                            hir_def::hir::BinaryOp::Assignment { .. } => unreachable!(), // handled above
1177                        },
1178                        lhs_op,
1179                        rhs_op,
1180                    ),
1181                    expr_id.into(),
1182                );
1183                Ok(Some(current))
1184            }
1185            &Expr::Assignment { target, value } => {
1186                let Some((value, mut current)) = self.lower_expr_as_place(current, value, true)?
1187                else {
1188                    return Ok(None);
1189                };
1190                self.push_fake_read(current, value, expr_id.into());
1191                let resolver_guard =
1192                    self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id);
1193                current = self.pattern_match_assignment(current, value, target)?;
1194                self.resolver.reset_to_guard(resolver_guard);
1195                Ok(Some(current))
1196            }
1197            &Expr::Range { lhs, rhs, range_type: _ } => {
1198                let ty = self.expr_ty_without_adjust(expr_id);
1199                let Some((adt, subst)) = ty.as_adt() else {
1200                    return Err(MirLowerError::TypeError("Range type is not adt"));
1201                };
1202                let AdtId::StructId(st) = adt else {
1203                    return Err(MirLowerError::TypeError("Range type is not struct"));
1204                };
1205                let mut lp = None;
1206                let mut rp = None;
1207                if let Some(it) = lhs {
1208                    let Some((o, c)) = self.lower_expr_to_some_operand(it, current)? else {
1209                        return Ok(None);
1210                    };
1211                    lp = Some(o);
1212                    current = c;
1213                }
1214                if let Some(it) = rhs {
1215                    let Some((o, c)) = self.lower_expr_to_some_operand(it, current)? else {
1216                        return Ok(None);
1217                    };
1218                    rp = Some(o);
1219                    current = c;
1220                }
1221                self.push_assignment(
1222                    current,
1223                    place,
1224                    Rvalue::Aggregate(
1225                        AggregateKind::Adt(st.into(), subst.store()),
1226                        st.fields(self.db)
1227                            .fields()
1228                            .iter()
1229                            .map(|it| {
1230                                let o = match it.1.name.as_str() {
1231                                    "start" => lp.take(),
1232                                    "end" => rp.take(),
1233                                    "exhausted" => Some(Operand::from_bytes(
1234                                        Box::new([0]),
1235                                        Ty::new_bool(self.interner()),
1236                                    )),
1237                                    _ => None,
1238                                };
1239                                o.ok_or(MirLowerError::UnresolvedField)
1240                            })
1241                            .collect::<Result<'_, _>>()?,
1242                    ),
1243                    expr_id.into(),
1244                );
1245                Ok(Some(current))
1246            }
1247            Expr::Closure { closure_kind: ClosureKind::Closure, .. } => {
1248                let ty = self.expr_ty_without_adjust(expr_id);
1249                let TyKind::Closure(id, _) = ty.kind() else {
1250                    not_supported!("closure with non closure type");
1251                };
1252                self.result.closures.push(id.0);
1253                let closure_data = &self.infer.closures_data[&id.0.loc(self.db).expr];
1254
1255                let span = |sources: &[CaptureSourceStack]| match sources
1256                    .first()
1257                    .map(|it| it.final_source().unpack())
1258                {
1259                    Some(ExprOrPatId::ExprId(it)) => it.into(),
1260                    Some(ExprOrPatId::PatId(it)) => it.into(),
1261                    None => MirSpan::Unknown,
1262                };
1263                let convert_place = |this: &mut Self, place: &HirPlace| {
1264                    let (HirPlaceBase::Local(local) | HirPlaceBase::Upvar { var_id: local, .. }) =
1265                        place.base
1266                    else {
1267                        not_supported!("non-local capture");
1268                    };
1269                    Ok(Place {
1270                        local: this.binding_local(local)?,
1271                        projection: Projection::new_from_iter(convert_closure_capture_projections(
1272                            self.db, place,
1273                        ))
1274                        .store(),
1275                    })
1276                };
1277
1278                for (place, _, sources) in &closure_data.fake_reads {
1279                    let p = convert_place(self, place)?;
1280                    self.push_fake_read(current, p.as_ref(), span(sources));
1281                }
1282
1283                let captures = closure_data.min_captures.values().flatten();
1284                let mut operands = vec![];
1285                for capture in captures {
1286                    let p = convert_place(self, &capture.place)?;
1287                    match capture.info.capture_kind {
1288                        UpvarCapture::ByRef(bk) => {
1289                            let tmp_ty = capture.captured_ty(self.db);
1290                            // FIXME: Handle more than one span.
1291                            let capture_span = span(&capture.info.sources);
1292                            let tmp = self.temp(tmp_ty, current, capture_span)?.into();
1293                            self.push_assignment(
1294                                current,
1295                                tmp,
1296                                Rvalue::Ref(BorrowKind::from_hir(bk), p),
1297                                capture_span,
1298                            );
1299                            operands
1300                                .push(Operand { kind: OperandKind::Move(tmp.store()), span: None });
1301                        }
1302                        UpvarCapture::ByValue => {
1303                            operands.push(Operand { kind: OperandKind::Move(p), span: None })
1304                        }
1305                        UpvarCapture::ByUse => not_supported!("capture by use"),
1306                    }
1307                }
1308                self.push_assignment(
1309                    current,
1310                    place,
1311                    Rvalue::Aggregate(AggregateKind::Closure(ty.store()), operands.into()),
1312                    expr_id.into(),
1313                );
1314                Ok(Some(current))
1315            }
1316            Expr::Closure { closure_kind, .. } => not_supported!("{closure_kind:?} closure"),
1317            Expr::Tuple { exprs } => {
1318                let Some(values) = exprs
1319                    .iter()
1320                    .map(|it| {
1321                        let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)? else {
1322                            return Ok(None);
1323                        };
1324                        current = c;
1325                        Ok(Some(o))
1326                    })
1327                    .collect::<Result<'_, Option<_>>>()?
1328                else {
1329                    return Ok(None);
1330                };
1331                let r = Rvalue::Aggregate(
1332                    AggregateKind::Tuple(self.expr_ty_without_adjust(expr_id).store()),
1333                    values,
1334                );
1335                self.push_assignment(current, place, r, expr_id.into());
1336                Ok(Some(current))
1337            }
1338            Expr::Array(l) => match l {
1339                Array::ElementList { elements, .. } => {
1340                    let elem_ty = match self.expr_ty_without_adjust(expr_id).kind() {
1341                        TyKind::Array(ty, _) => ty,
1342                        _ => {
1343                            return Err(MirLowerError::TypeError(
1344                                "Array expression with non array type",
1345                            ));
1346                        }
1347                    };
1348                    let Some(values) = elements
1349                        .iter()
1350                        .map(|it| {
1351                            let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)?
1352                            else {
1353                                return Ok(None);
1354                            };
1355                            current = c;
1356                            Ok(Some(o))
1357                        })
1358                        .collect::<Result<'_, Option<_>>>()?
1359                    else {
1360                        return Ok(None);
1361                    };
1362                    let r = Rvalue::Aggregate(AggregateKind::Array(elem_ty.store()), values);
1363                    self.push_assignment(current, place, r, expr_id.into());
1364                    Ok(Some(current))
1365                }
1366                Array::Repeat { initializer, .. } => {
1367                    let Some((init, current)) =
1368                        self.lower_expr_to_some_operand(*initializer, current)?
1369                    else {
1370                        return Ok(None);
1371                    };
1372                    let len = match self.expr_ty_without_adjust(expr_id).kind() {
1373                        TyKind::Array(_, len) => len,
1374                        _ => {
1375                            return Err(MirLowerError::TypeError(
1376                                "Array repeat expression with non array type",
1377                            ));
1378                        }
1379                    };
1380                    let r = Rvalue::Repeat(init, len.store());
1381                    self.push_assignment(current, place, r, expr_id.into());
1382                    Ok(Some(current))
1383                }
1384            },
1385            Expr::Literal(l) => {
1386                let ty = self.expr_ty_without_adjust(expr_id);
1387                let op = self.lower_literal_to_operand(ty, l)?;
1388                self.push_assignment(current, place, op.into(), expr_id.into());
1389                Ok(Some(current))
1390            }
1391            Expr::Underscore => Ok(Some(current)),
1392            Expr::IncludeBytes => not_supported!("include_bytes!()"),
1393        }
1394    }
1395
1396    fn push_field_projection(
1397        &mut self,
1398        place: &mut PlaceRef<'db>,
1399        expr_id: ExprId,
1400    ) -> Result<'db, ()> {
1401        if let Expr::Field { expr, name } = &self.store[expr_id] {
1402            if let TyKind::Tuple(tys) = self.expr_ty_after_adjustments(*expr).kind() {
1403                let index =
1404                    name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))?
1405                        as u32;
1406                if tys.get(index as usize).is_none() {
1407                    return Err(MirLowerError::TypeError("tuple field index out of range"));
1408                }
1409                *place = place.project(ProjectionElem::Field(FieldIndex(index)));
1410            } else {
1411                let field = self
1412                    .infer
1413                    .field_resolution(expr_id)
1414                    .ok_or(MirLowerError::UnresolvedField)?
1415                    .either(|f| f.local_id.into(), |t| FieldIndex(t.index));
1416                *place = place.project(ProjectionElem::Field(field));
1417            }
1418        } else {
1419            not_supported!("")
1420        }
1421        Ok(())
1422    }
1423
1424    fn lower_literal_or_const_to_operand(
1425        &mut self,
1426        ty: Ty<'db>,
1427        loc: &ExprId,
1428    ) -> Result<'db, Operand> {
1429        match &self.store[*loc] {
1430            Expr::Literal(l) => self.lower_literal_to_operand(ty, l),
1431            Expr::Path(c) => {
1432                let owner = self.owner;
1433                let db = self.db;
1434                let unresolved_name = || {
1435                    MirLowerError::unresolved_path(
1436                        self.db,
1437                        c,
1438                        DisplayTarget::from_crate(db, owner.krate(db)),
1439                        self.owner.expression_store_owner(self.db),
1440                        self.store,
1441                    )
1442                };
1443                let pr = self
1444                    .resolver
1445                    .resolve_path_in_value_ns(self.db, c, HygieneId::ROOT)
1446                    .ok_or_else(unresolved_name)?;
1447                match pr {
1448                    ResolveValueResult::ValueNs(v) => {
1449                        if let ValueNs::ConstId(c) = v {
1450                            self.lower_const_to_operand(
1451                                GenericArgs::empty(self.interner()),
1452                                c.into(),
1453                            )
1454                        } else {
1455                            not_supported!("bad path in range pattern");
1456                        }
1457                    }
1458                    ResolveValueResult::Partial(_, _) => {
1459                        not_supported!("associated constants in range pattern")
1460                    }
1461                }
1462            }
1463            _ => {
1464                not_supported!("only `char` and numeric types are allowed in range patterns");
1465            }
1466        }
1467    }
1468
1469    fn lower_literal_to_operand(&mut self, ty: Ty<'db>, l: &Literal) -> Result<'db, Operand> {
1470        let size = || {
1471            self.db
1472                .layout_of_ty(
1473                    ty.store(),
1474                    ParamEnvAndCrate { param_env: self.env, krate: self.krate() }.store(),
1475                )
1476                .map(|it| it.size.bytes_usize())
1477        };
1478        const USIZE_SIZE: usize = size_of::<usize>();
1479        let bytes: Box<[_]> = match l {
1480            hir_def::hir::Literal::String(b) => {
1481                let b = b.as_str();
1482                let mut data = [0; { 2 * USIZE_SIZE }];
1483                data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes());
1484                data[USIZE_SIZE..].copy_from_slice(&b.len().to_le_bytes());
1485                let mm = MemoryMap::simple(b.as_bytes().into());
1486                return Ok(Operand::from_concrete_const(Box::new(data), mm, ty));
1487            }
1488            hir_def::hir::Literal::CString(b) => {
1489                let bytes = b.iter().copied().chain(iter::once(0)).collect::<Box<_>>();
1490
1491                let mut data = [0; { 2 * USIZE_SIZE }];
1492                data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes());
1493                data[USIZE_SIZE..].copy_from_slice(&bytes.len().to_le_bytes());
1494                let mm = MemoryMap::simple(bytes);
1495                return Ok(Operand::from_concrete_const(Box::new(data), mm, ty));
1496            }
1497            hir_def::hir::Literal::ByteString(b) => {
1498                let mut data = [0; { 2 * USIZE_SIZE }];
1499                data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes());
1500                data[USIZE_SIZE..].copy_from_slice(&b.len().to_le_bytes());
1501                let mm = MemoryMap::simple(b.clone());
1502                return Ok(Operand::from_concrete_const(Box::new(data), mm, ty));
1503            }
1504            hir_def::hir::Literal::Char(c) => Box::new(u32::from(*c).to_le_bytes()),
1505            hir_def::hir::Literal::Bool(b) => Box::new([*b as u8]),
1506            hir_def::hir::Literal::Int(it, _) => Box::from(&it.to_le_bytes()[0..size()?]),
1507            hir_def::hir::Literal::Uint(it, _) => Box::from(&it.to_le_bytes()[0..size()?]),
1508            hir_def::hir::Literal::Float(f, _) => match size()? {
1509                16 => Box::new(f.to_f128().to_bits().to_le_bytes()),
1510                8 => Box::new(f.to_f64().to_bits().to_le_bytes()),
1511                4 => Box::new(f.to_f32().to_bits().to_le_bytes()),
1512                2 => Box::new(u16::try_from(f.to_f16().to_bits()).unwrap().to_le_bytes()),
1513                _ => {
1514                    return Err(MirLowerError::TypeError(
1515                        "float with size other than 2, 4, 8 or 16 bytes",
1516                    ));
1517                }
1518            },
1519        };
1520        Ok(Operand::from_concrete_const(bytes, MemoryMap::default(), ty))
1521    }
1522
1523    fn new_basic_block(&mut self) -> BasicBlockId {
1524        self.result.basic_blocks.alloc(BasicBlock::default())
1525    }
1526
1527    fn lower_const(
1528        &mut self,
1529        const_id: GeneralConstId<'db>,
1530        prev_block: BasicBlockId,
1531        place: PlaceRef<'db>,
1532        subst: GenericArgs<'db>,
1533        span: MirSpan,
1534    ) -> Result<'db, ()> {
1535        let c = self.lower_const_to_operand(subst, const_id)?;
1536        self.push_assignment(prev_block, place, c.into(), span);
1537        Ok(())
1538    }
1539
1540    fn lower_const_to_operand(
1541        &mut self,
1542        subst: GenericArgs<'db>,
1543        const_id: GeneralConstId<'db>,
1544    ) -> Result<'db, Operand> {
1545        let konst = Const::new_unevaluated(
1546            self.interner(),
1547            UnevaluatedConst { def: const_id.into(), args: subst },
1548        );
1549        let ty = match const_id {
1550            GeneralConstId::ConstId(id) => self.db.value_ty(id.into()).unwrap(),
1551            GeneralConstId::StaticId(id) => self.db.value_ty(id.into()).unwrap(),
1552            GeneralConstId::AnonConstId(id) => id.loc(self.db).ty.get(),
1553        };
1554        let ty = ty.instantiate(self.interner(), subst).skip_norm_wip();
1555        Ok(Operand {
1556            kind: OperandKind::Constant { konst: konst.store(), ty: ty.store() },
1557            span: None,
1558        })
1559    }
1560
1561    fn write_bytes_to_place(
1562        &mut self,
1563        prev_block: BasicBlockId,
1564        place: PlaceRef<'db>,
1565        cv: Box<[u8]>,
1566        ty: Ty<'db>,
1567        span: MirSpan,
1568    ) -> Result<'db, ()> {
1569        self.push_assignment(prev_block, place, Operand::from_bytes(cv, ty).into(), span);
1570        Ok(())
1571    }
1572
1573    fn lower_enum_variant(
1574        &mut self,
1575        variant_id: EnumVariantId,
1576        prev_block: BasicBlockId,
1577        place: PlaceRef<'db>,
1578        ty: Ty<'db>,
1579        fields: Box<[Operand]>,
1580        span: MirSpan,
1581    ) -> Result<'db, BasicBlockId> {
1582        let subst = match ty.kind() {
1583            TyKind::Adt(_, subst) => subst,
1584            _ => implementation_error!("Non ADT enum"),
1585        };
1586        self.push_assignment(
1587            prev_block,
1588            place,
1589            Rvalue::Aggregate(AggregateKind::Adt(variant_id.into(), subst.store()), fields),
1590            span,
1591        );
1592        Ok(prev_block)
1593    }
1594
1595    fn lower_call_and_args(
1596        &mut self,
1597        func: Operand,
1598        args: impl Iterator<Item = ExprId>,
1599        place: PlaceRef<'db>,
1600        mut current: BasicBlockId,
1601        is_uninhabited: bool,
1602        span: MirSpan,
1603    ) -> Result<'db, Option<BasicBlockId>> {
1604        let Some(args) = args
1605            .map(|arg| {
1606                if let Some((temp, c)) = self.lower_expr_to_some_operand(arg, current)? {
1607                    current = c;
1608                    Ok(Some(temp))
1609                } else {
1610                    Ok(None)
1611                }
1612            })
1613            .collect::<Result<'_, Option<Vec<_>>>>()?
1614        else {
1615            return Ok(None);
1616        };
1617        self.lower_call(func, args.into(), place, current, is_uninhabited, span)
1618    }
1619
1620    fn lower_call(
1621        &mut self,
1622        func: Operand,
1623        args: Box<[Operand]>,
1624        place: PlaceRef<'db>,
1625        current: BasicBlockId,
1626        is_uninhabited: bool,
1627        span: MirSpan,
1628    ) -> Result<'db, Option<BasicBlockId>> {
1629        let b = if is_uninhabited { None } else { Some(self.new_basic_block()) };
1630        self.set_terminator(
1631            current,
1632            TerminatorKind::Call {
1633                func,
1634                args,
1635                destination: place.store(),
1636                target: b,
1637                cleanup: None,
1638                from_hir_call: true,
1639            },
1640            span,
1641        );
1642        Ok(b)
1643    }
1644
1645    fn is_unterminated(&mut self, source: BasicBlockId) -> bool {
1646        self.result.basic_blocks[source].terminator.is_none()
1647    }
1648
1649    fn set_terminator(&mut self, source: BasicBlockId, terminator: TerminatorKind, span: MirSpan) {
1650        self.result.basic_blocks[source].terminator = Some(Terminator { span, kind: terminator });
1651    }
1652
1653    fn set_goto(&mut self, source: BasicBlockId, target: BasicBlockId, span: MirSpan) {
1654        self.set_terminator(source, TerminatorKind::Goto { target }, span);
1655    }
1656
1657    fn expr_ty_without_adjust(&self, e: ExprId) -> Ty<'db> {
1658        self.infer.expr_ty(e)
1659    }
1660
1661    fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty<'db> {
1662        let mut ty = None;
1663        if let Some(it) = self.infer.expr_adjustments.get(&e)
1664            && let Some(it) = it.last()
1665        {
1666            ty = Some(it.target.as_ref());
1667        }
1668        ty.unwrap_or_else(|| self.expr_ty_without_adjust(e))
1669    }
1670
1671    fn push_statement(&mut self, block: BasicBlockId, statement: Statement) {
1672        self.result.basic_blocks[block].statements.push(statement);
1673    }
1674
1675    fn push_fake_read(&mut self, block: BasicBlockId, p: PlaceRef<'db>, span: MirSpan) {
1676        self.push_statement(block, StatementKind::FakeRead(p.store()).with_span(span));
1677    }
1678
1679    fn push_assignment(
1680        &mut self,
1681        block: BasicBlockId,
1682        place: PlaceRef<'db>,
1683        rvalue: Rvalue,
1684        span: MirSpan,
1685    ) {
1686        self.push_statement(block, StatementKind::Assign(place.store(), rvalue).with_span(span));
1687    }
1688
1689    fn discr_temp_place(&mut self, current: BasicBlockId) -> PlaceRef<'db> {
1690        match &self.discr_temp {
1691            Some(it) => it.as_ref(),
1692            None => {
1693                // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well
1694                let discr_ty = Ty::new_int(self.interner(), rustc_type_ir::IntTy::I128);
1695                let tmp: PlaceRef<'_> = self
1696                    .temp(discr_ty, current, MirSpan::Unknown)
1697                    .expect("discr_ty is never unsized")
1698                    .into();
1699                self.discr_temp = Some(tmp.store());
1700                tmp
1701            }
1702        }
1703    }
1704
1705    fn lower_loop(
1706        &mut self,
1707        prev_block: BasicBlockId,
1708        place: PlaceRef<'db>,
1709        label: Option<LabelId>,
1710        span: MirSpan,
1711        f: impl FnOnce(&mut MirLowerCtx<'_, 'db>, BasicBlockId) -> Result<'db, ()>,
1712    ) -> Result<'db, Option<BasicBlockId>> {
1713        let begin = self.new_basic_block();
1714        let prev = self.current_loop_blocks.replace(LoopBlocks {
1715            begin,
1716            end: None,
1717            place: place.store(),
1718            drop_scope_index: self.drop_scopes.len(),
1719        });
1720        let prev_label = if let Some(label) = label {
1721            // We should generate the end now, to make sure that it wouldn't change later. It is
1722            // bad as we may emit end (unnecessary unreachable block) for unterminating loop, but
1723            // it should not affect correctness.
1724            self.current_loop_end()?;
1725            self.labeled_loop_blocks
1726                .insert(label, self.current_loop_blocks.as_ref().unwrap().clone())
1727        } else {
1728            None
1729        };
1730        self.set_goto(prev_block, begin, span);
1731        f(self, begin)?;
1732        let my = mem::replace(&mut self.current_loop_blocks, prev).ok_or(
1733            MirLowerError::ImplementationError("current_loop_blocks is corrupt".to_owned()),
1734        )?;
1735        if let Some(prev) = prev_label {
1736            self.labeled_loop_blocks.insert(label.unwrap(), prev);
1737        }
1738        Ok(my.end)
1739    }
1740
1741    fn has_adjustments(&self, expr_id: ExprId) -> bool {
1742        !self.infer.expr_adjustments.get(&expr_id).map(|it| it.is_empty()).unwrap_or(true)
1743    }
1744
1745    fn merge_blocks(
1746        &mut self,
1747        b1: Option<BasicBlockId>,
1748        b2: Option<BasicBlockId>,
1749        span: MirSpan,
1750    ) -> Option<BasicBlockId> {
1751        match (b1, b2) {
1752            (None, None) => None,
1753            (None, Some(b)) | (Some(b), None) => Some(b),
1754            (Some(b1), Some(b2)) => {
1755                let bm = self.new_basic_block();
1756                self.set_goto(b1, bm, span);
1757                self.set_goto(b2, bm, span);
1758                Some(bm)
1759            }
1760        }
1761    }
1762
1763    fn current_loop_end(&mut self) -> Result<'db, BasicBlockId> {
1764        let r = match self
1765            .current_loop_blocks
1766            .as_mut()
1767            .ok_or(MirLowerError::ImplementationError(
1768                "Current loop access out of loop".to_owned(),
1769            ))?
1770            .end
1771        {
1772            Some(it) => it,
1773            None => {
1774                let s = self.new_basic_block();
1775                self.current_loop_blocks
1776                    .as_mut()
1777                    .ok_or(MirLowerError::ImplementationError(
1778                        "Current loop access out of loop".to_owned(),
1779                    ))?
1780                    .end = Some(s);
1781                s
1782            }
1783        };
1784        Ok(r)
1785    }
1786
1787    fn is_uninhabited(&self, expr_id: ExprId) -> bool {
1788        is_ty_uninhabited_from(
1789            &self.infcx,
1790            self.infer.expr_ty(expr_id),
1791            self.owner.module(self.db),
1792            self.env,
1793        )
1794    }
1795
1796    /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and
1797    /// `Drop` in the appropriated places.
1798    fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<'db, ()> {
1799        let l = self.binding_local(b)?;
1800        self.push_storage_live_for_local(l, current, MirSpan::BindingId(b))
1801    }
1802
1803    fn push_storage_live_for_local(
1804        &mut self,
1805        l: LocalId,
1806        current: BasicBlockId,
1807        span: MirSpan,
1808    ) -> Result<'db, ()> {
1809        self.drop_scopes.last_mut().unwrap().locals.push(l);
1810        self.push_statement(current, StatementKind::StorageLive(l).with_span(span));
1811        Ok(())
1812    }
1813
1814    fn lower_block_to_place(
1815        &mut self,
1816        statements: &[hir_def::hir::Statement],
1817        mut current: BasicBlockId,
1818        tail: Option<ExprId>,
1819        place: PlaceRef<'db>,
1820        span: MirSpan,
1821    ) -> Result<'db, Option<Idx<BasicBlock>>> {
1822        let scope = self.push_drop_scope();
1823        for statement in statements.iter() {
1824            match statement {
1825                hir_def::hir::Statement::Let { pat, initializer, else_branch, type_ref: _ } => {
1826                    if let Some(expr_id) = initializer {
1827                        let else_block;
1828                        let Some((init_place, c)) =
1829                            self.lower_expr_as_place(current, *expr_id, true)?
1830                        else {
1831                            scope.pop_assume_dropped(self);
1832                            return Ok(None);
1833                        };
1834                        current = c;
1835                        self.push_fake_read(current, init_place, span);
1836                        // Using the initializer for the resolver scope is good enough for us, as it cannot create new declarations
1837                        // and has all declarations of the `let`.
1838                        let resolver_guard = self.resolver.update_to_inner_scope(
1839                            self.db,
1840                            self.store_owner,
1841                            *expr_id,
1842                        );
1843                        (current, else_block) =
1844                            self.pattern_match(current, None, init_place, *pat)?;
1845                        self.resolver.reset_to_guard(resolver_guard);
1846                        match (else_block, else_branch) {
1847                            (None, _) => (),
1848                            (Some(else_block), None) => {
1849                                self.set_terminator(else_block, TerminatorKind::Unreachable, span);
1850                            }
1851                            (Some(else_block), Some(else_branch)) => {
1852                                if let Some((_, b)) =
1853                                    self.lower_expr_as_place(else_block, *else_branch, true)?
1854                                {
1855                                    self.set_terminator(b, TerminatorKind::Unreachable, span);
1856                                }
1857                            }
1858                        }
1859                    } else {
1860                        let mut err = None;
1861                        self.store.walk_bindings_in_pat(*pat, |b| {
1862                            if let Err(e) = self.push_storage_live(b, current) {
1863                                err = Some(e);
1864                            }
1865                        });
1866                        if let Some(e) = err {
1867                            return Err(e);
1868                        }
1869                    }
1870                }
1871                &hir_def::hir::Statement::Expr { expr, has_semi: _ } => {
1872                    let scope2 = self.push_drop_scope();
1873                    let Some((p, c)) = self.lower_expr_as_place(current, expr, true)? else {
1874                        scope2.pop_assume_dropped(self);
1875                        scope.pop_assume_dropped(self);
1876                        return Ok(None);
1877                    };
1878                    self.push_fake_read(c, p, expr.into());
1879                    current = scope2.pop_and_drop(self, c, expr.into());
1880                }
1881                hir_def::hir::Statement::Item(_) => (),
1882            }
1883        }
1884        if let Some(tail) = tail {
1885            let Some(c) = self.lower_expr_to_place(tail, place, current)? else {
1886                scope.pop_assume_dropped(self);
1887                return Ok(None);
1888            };
1889            current = c;
1890        }
1891        current = scope.pop_and_drop(self, current, span);
1892        Ok(Some(current))
1893    }
1894
1895    fn lower_params_and_bindings(
1896        &mut self,
1897        params: impl Iterator<Item = (PatId, Ty<'db>)> + Clone,
1898        self_binding: Option<(BindingId, Ty<'db>)>,
1899        pick_binding: impl Fn(BindingId) -> bool,
1900    ) -> Result<'db, BasicBlockId> {
1901        let base_param_count = self.result.param_locals.len();
1902        let self_binding = match self_binding {
1903            Some((self_binding, ty)) => {
1904                let local_id = self.result.locals.alloc(Local { ty: ty.store() });
1905                self.drop_scopes.last_mut().unwrap().locals.push(local_id);
1906                self.result.binding_locals.insert(self_binding, local_id);
1907                self.result.param_locals.push(local_id);
1908                Some(self_binding)
1909            }
1910            None => None,
1911        };
1912        self.result.param_locals.extend(params.clone().map(|(it, ty)| {
1913            let local_id = self.result.locals.alloc(Local { ty: ty.store() });
1914            self.drop_scopes.last_mut().unwrap().locals.push(local_id);
1915            if let Pat::Bind { id, subpat: None } = self.store[it]
1916                && matches!(
1917                    self.store[id].mode,
1918                    BindingAnnotation::Unannotated | BindingAnnotation::Mutable
1919                )
1920            {
1921                self.result.binding_locals.insert(id, local_id);
1922            }
1923            local_id
1924        }));
1925        // and then rest of bindings
1926        for (id, _) in self.store.bindings() {
1927            if !pick_binding(id) {
1928                continue;
1929            }
1930            if !self.result.binding_locals.contains_idx(id) {
1931                self.result.binding_locals.insert(
1932                    id,
1933                    self.result.locals.alloc(Local { ty: self.infer.binding_ty(id).store() }),
1934                );
1935            }
1936        }
1937        let mut current = self.result.start_block;
1938        if let Some(self_binding) = self_binding {
1939            let local = self.result.param_locals.clone()[base_param_count];
1940            if local != self.binding_local(self_binding)? {
1941                let r = self.match_self_param(self_binding, current, local)?;
1942                if let Some(b) = r.1 {
1943                    self.set_terminator(b, TerminatorKind::Unreachable, MirSpan::SelfParam);
1944                }
1945                current = r.0;
1946            }
1947        }
1948        let local_params = self
1949            .result
1950            .param_locals
1951            .clone()
1952            .into_iter()
1953            .skip(base_param_count + self_binding.is_some() as usize);
1954        for ((param, _), local) in params.zip(local_params) {
1955            if let Pat::Bind { id, .. } = self.store[param]
1956                && local == self.binding_local(id)?
1957            {
1958                continue;
1959            }
1960            let r = self.pattern_match(current, None, local.into(), param)?;
1961            if let Some(b) = r.1 {
1962                self.set_terminator(b, TerminatorKind::Unreachable, param.into());
1963            }
1964            current = r.0;
1965        }
1966        Ok(current)
1967    }
1968
1969    fn binding_local(&self, b: BindingId) -> Result<'db, LocalId> {
1970        match self.result.binding_locals.get(b) {
1971            Some(it) => Ok(*it),
1972            None => {
1973                // FIXME: It should never happens, but currently it will happen in some cases, not sure when exactly.
1974                // never!("Using inaccessible local for binding is always a bug");
1975                Err(MirLowerError::InaccessibleLocal)
1976            }
1977        }
1978    }
1979
1980    fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> {
1981        let r = self.db.const_eval_discriminant(variant);
1982        match r {
1983            Ok(r) => Ok(r),
1984            Err(e) => {
1985                let edition = self.edition();
1986                let db = self.db;
1987                let loc = variant.lookup(db);
1988                let name = format!(
1989                    "{}::{}",
1990                    EnumSignature::of(db, loc.parent).name.display(db, edition),
1991                    loc.parent
1992                        .enum_variants(self.db)
1993                        .variant_name_by_id(variant)
1994                        .unwrap()
1995                        .display(db, edition),
1996                );
1997                Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
1998            }
1999        }
2000    }
2001
2002    fn edition(&self) -> Edition {
2003        self.krate().data(self.db).edition
2004    }
2005
2006    fn krate(&self) -> Crate {
2007        self.owner.krate(self.db)
2008    }
2009
2010    fn display_target(&self) -> DisplayTarget {
2011        DisplayTarget::from_crate(self.db, self.krate())
2012    }
2013
2014    fn drop_until_scope(
2015        &mut self,
2016        scope_index: usize,
2017        mut current: BasicBlockId,
2018        span: MirSpan,
2019    ) -> BasicBlockId {
2020        for scope in self.drop_scopes[scope_index..].to_vec().iter().rev() {
2021            self.emit_drop_and_storage_dead_for_scope(scope, &mut current, span);
2022        }
2023        current
2024    }
2025
2026    fn push_drop_scope(&mut self) -> DropScopeToken {
2027        self.drop_scopes.push(DropScope::default());
2028        DropScopeToken
2029    }
2030
2031    /// Don't call directly
2032    fn pop_drop_scope_assume_dropped_internal(&mut self) {
2033        self.drop_scopes.pop();
2034    }
2035
2036    /// Don't call directly
2037    fn pop_drop_scope_internal(
2038        &mut self,
2039        mut current: BasicBlockId,
2040        span: MirSpan,
2041    ) -> BasicBlockId {
2042        let scope = self.drop_scopes.pop().unwrap();
2043        self.emit_drop_and_storage_dead_for_scope(&scope, &mut current, span);
2044        current
2045    }
2046
2047    fn pop_drop_scope_assert_finished(
2048        &mut self,
2049        mut current: BasicBlockId,
2050        span: MirSpan,
2051    ) -> Result<'db, BasicBlockId> {
2052        current = self.pop_drop_scope_internal(current, span);
2053        if !self.drop_scopes.is_empty() {
2054            implementation_error!("Mismatched count between drop scope push and pops");
2055        }
2056        Ok(current)
2057    }
2058
2059    fn emit_drop_and_storage_dead_for_scope(
2060        &mut self,
2061        scope: &DropScope,
2062        current: &mut Idx<BasicBlock>,
2063        span: MirSpan,
2064    ) {
2065        for &l in scope.locals.iter().rev() {
2066            if !self.infcx.type_is_copy_modulo_regions(self.env, self.result.locals[l].ty.as_ref())
2067            {
2068                let prev = std::mem::replace(current, self.new_basic_block());
2069                self.set_terminator(
2070                    prev,
2071                    TerminatorKind::Drop {
2072                        place: PlaceRef::from(l).store(),
2073                        target: *current,
2074                        unwind: None,
2075                    },
2076                    span,
2077                );
2078            }
2079            self.push_statement(*current, StatementKind::StorageDead(l).with_span(span));
2080        }
2081    }
2082}
2083
2084fn convert_closure_capture_projections(
2085    _db: &dyn HirDatabase,
2086    place: &HirPlace,
2087) -> impl Iterator<Item = PlaceElem> {
2088    place.projections.iter().enumerate().map(|(i, proj)| match proj.kind {
2089        HirProjectionKind::Deref => ProjectionElem::Deref,
2090        HirProjectionKind::Field { field_idx, variant_idx: _ } => {
2091            let ty = place.ty_before_projection(i);
2092            match ty.kind() {
2093                TyKind::Tuple(_) => ProjectionElem::Field(FieldIndex(field_idx)),
2094                TyKind::Adt(_, _) => {
2095                    let local_field_id = LocalFieldId::from_raw(RawIdx::from_u32(field_idx));
2096                    ProjectionElem::Field(local_field_id.into())
2097                }
2098                _ => panic!("unexpected type"),
2099            }
2100        }
2101        _ => panic!("unexpected projection"),
2102    })
2103}
2104
2105fn cast_kind<'db>(
2106    db: &'db dyn HirDatabase,
2107    source_ty: Ty<'db>,
2108    target_ty: Ty<'db>,
2109) -> Result<'db, CastKind> {
2110    let from = CastTy::from_ty(db, source_ty);
2111    let cast = CastTy::from_ty(db, target_ty);
2112    Ok(match (from, cast) {
2113        (Some(CastTy::Ptr(..) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
2114            CastKind::PointerExposeAddress
2115        }
2116        (Some(CastTy::Int(_)), Some(CastTy::Ptr(..))) => CastKind::PointerFromExposedAddress,
2117        (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => CastKind::IntToInt,
2118        (Some(CastTy::FnPtr), Some(CastTy::Ptr(..))) => CastKind::FnPtrToPtr,
2119        (Some(CastTy::Float), Some(CastTy::Int(_))) => CastKind::FloatToInt,
2120        (Some(CastTy::Int(_)), Some(CastTy::Float)) => CastKind::IntToFloat,
2121        (Some(CastTy::Float), Some(CastTy::Float)) => CastKind::FloatToFloat,
2122        (Some(CastTy::Ptr(..)), Some(CastTy::Ptr(..))) => CastKind::PtrToPtr,
2123        _ => not_supported!("Unknown cast between {source_ty:?} and {target_ty:?}"),
2124    })
2125}
2126
2127#[salsa::tracked(returns(as_ref), cycle_result = mir_body_for_closure_cycle_result)]
2128pub fn mir_body_for_closure_query<'db>(
2129    db: &'db dyn HirDatabase,
2130    closure: InternedClosureId<'db>,
2131) -> Result<'db, MirBody<'db>> {
2132    let InternedClosure { owner: body_owner, expr, .. } = closure.loc(db);
2133    let store = ExpressionStore::of(db, body_owner.expression_store_owner(db));
2134    let infer = InferenceResult::of(db, body_owner);
2135    let Expr::Closure { args, body: root, .. } = &store[expr] else {
2136        implementation_error!("closure expression is not closure");
2137    };
2138    let crate::next_solver::TyKind::Closure(_, substs) = infer.expr_ty(expr).kind() else {
2139        implementation_error!("closure expression is not closure");
2140    };
2141    let kind = substs.as_closure().kind();
2142    let captures = infer.closures_data[&expr].min_captures.values().flatten();
2143    let mut ctx = MirLowerCtx::new(db, body_owner, store, infer);
2144
2145    // 0 is return local
2146    ctx.result.locals.alloc(Local { ty: infer.expr_ty(*root).store() });
2147    let closure_local = ctx.result.locals.alloc(Local {
2148        ty: match kind {
2149            rustc_type_ir::ClosureKind::FnOnce => infer.expr_ty(expr),
2150            rustc_type_ir::ClosureKind::FnMut => Ty::new_ref(
2151                ctx.interner(),
2152                Region::error(ctx.interner()),
2153                infer.expr_ty(expr),
2154                Mutability::Mut,
2155            ),
2156            rustc_type_ir::ClosureKind::Fn => Ty::new_ref(
2157                ctx.interner(),
2158                Region::error(ctx.interner()),
2159                infer.expr_ty(expr),
2160                Mutability::Not,
2161            ),
2162        }
2163        .store(),
2164    });
2165    ctx.result.param_locals.push(closure_local);
2166
2167    let sig = ctx.interner().signature_unclosure(substs.as_closure().sig(), Safety::Safe);
2168    let resolver_guard = ctx.resolver.update_to_inner_scope(db, ctx.store_owner, expr);
2169    let current = ctx.lower_params_and_bindings(
2170        args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)),
2171        None,
2172        |_| true,
2173    )?;
2174
2175    // Push local for every upvar in the closure. rustc doesn't do that, but we have to so we have locals
2176    // to associate with upvars for borrowck.
2177    let is_by_ref_closure = match kind {
2178        rustc_type_ir::ClosureKind::Fn | rustc_type_ir::ClosureKind::FnMut => true,
2179        rustc_type_ir::ClosureKind::FnOnce => false,
2180    };
2181    let mut upvar_map: FxHashMap<LocalId, Vec<(&CapturedPlace, LocalId)>> = FxHashMap::default();
2182    for (capture_idx, capture) in captures.enumerate() {
2183        let capture_local = ctx.result.locals.alloc(Local { ty: capture.captured_ty(db).store() });
2184        ctx.push_storage_live_for_local(capture_local, current, MirSpan::Unknown)?;
2185        let mut projections = Vec::with_capacity(usize::from(is_by_ref_closure) + 1);
2186        if is_by_ref_closure {
2187            projections.push(ProjectionElem::Deref);
2188        }
2189        projections.push(ProjectionElem::Field(FieldIndex(capture_idx as u32)));
2190        let capture_param_place = Place {
2191            local: closure_local,
2192            projection: Projection::new_from_slice(&projections).store(),
2193        };
2194        let capture_local_place =
2195            Place { local: capture_local, projection: Projection::new_from_slice(&[]).store() };
2196        let capture_local_rvalue =
2197            Rvalue::Use(Operand { kind: OperandKind::Move(capture_param_place), span: None });
2198        ctx.push_assignment(
2199            current,
2200            capture_local_place.as_ref(),
2201            capture_local_rvalue,
2202            MirSpan::Unknown,
2203        );
2204
2205        let local = capture.captured_local();
2206        let local = ctx.binding_local(local)?;
2207        upvar_map.entry(local).or_default().push((capture, capture_local));
2208
2209        ctx.result
2210            .upvar_locals
2211            .entry(capture.captured_local())
2212            .or_default()
2213            .push((capture_local, capture.place.clone()));
2214    }
2215
2216    ctx.resolver.reset_to_guard(resolver_guard);
2217    if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? {
2218        let current = ctx.pop_drop_scope_assert_finished(current, root.into())?;
2219        ctx.set_terminator(current, TerminatorKind::Return, (*root).into());
2220    }
2221    let mut err = None;
2222    ctx.result.walk_places(|mir_place| {
2223        let mir_projections = mir_place.projection.lookup();
2224        if let Some(hir_places) = upvar_map.get(&mir_place.local) {
2225            let projections = hir_places.iter().find_map(|hir_place| {
2226                let iter = mir_projections
2227                    .iter()
2228                    .cloned()
2229                    .zip_longest(convert_closure_capture_projections(db, &hir_place.0.place))
2230                    .enumerate();
2231
2232                for (idx, item) in iter {
2233                    match item {
2234                        EitherOrBoth::Both(mir, hir) => {
2235                            if mir != hir {
2236                                // Not this place.
2237                                return None;
2238                            }
2239                        }
2240                        EitherOrBoth::Right(_) => {
2241                            // FIXME: This can happen in fake reads. I believe this is a bug. So we change the fake read's meaning.
2242                            // never!(
2243                            //     "mir upvar place shorter than hir upvar place; this should not happen, \
2244                            //         capture analysis should have picked the shorter place"
2245                            // );
2246                            // return None;
2247                            return Some((mir_projections.len(), hir_place));
2248                        }
2249                        // This place, but truncated.
2250                        EitherOrBoth::Left(_) => return Some((idx, hir_place)),
2251                    }
2252                }
2253                // Exactly this place.
2254                Some((hir_place.0.place.projections.len(), hir_place))
2255            });
2256            match projections {
2257                Some((skip_projections_up_to, (hir_place, upvar_local))) => {
2258                    mir_place.local = *upvar_local;
2259                    let maybe_deref: &[PlaceElem] =
2260                        if hir_place.is_by_ref() { &[ProjectionElem::Deref] } else { &[] };
2261                    mir_place.projection = Projection::new_from_iter(
2262                        maybe_deref
2263                            .iter()
2264                            .copied()
2265                            .chain(mir_projections[skip_projections_up_to..].iter().copied()),
2266                    )
2267                    .store();
2268                }
2269                None => err = Some(mir_place.clone()),
2270            }
2271        }
2272    });
2273    ctx.result.binding_locals = ctx
2274        .result
2275        .binding_locals
2276        .into_iter()
2277        .filter(|it| ctx.store.binding_owner(it.0) == Some(expr))
2278        .collect();
2279    if let Some(err) = err {
2280        return Err(MirLowerError::UnresolvedUpvar(err));
2281    }
2282    ctx.result.shrink_to_fit();
2283    Ok(ctx.result)
2284}
2285
2286#[salsa::tracked(returns(as_ref), cycle_result = mir_body_cycle_result)]
2287pub fn mir_body_query<'db>(
2288    db: &'db dyn HirDatabase,
2289    def: InferBodyId<'db>,
2290) -> Result<'db, MirBody<'db>> {
2291    let krate = def.krate(db);
2292    let edition = krate.data(db).edition;
2293    let detail = match def {
2294        InferBodyId::DefWithBodyId(DefWithBodyId::FunctionId(it)) => {
2295            FunctionSignature::of(db, it).name.display(db, edition).to_string()
2296        }
2297        InferBodyId::DefWithBodyId(DefWithBodyId::StaticId(it)) => {
2298            StaticSignature::of(db, it).name.display(db, edition).to_string()
2299        }
2300        InferBodyId::DefWithBodyId(DefWithBodyId::ConstId(it)) => ConstSignature::of(db, it)
2301            .name
2302            .clone()
2303            .unwrap_or_else(Name::missing)
2304            .display(db, edition)
2305            .to_string(),
2306        InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(it)) => {
2307            let loc = it.lookup(db);
2308            loc.name.display(db, edition).to_string()
2309        }
2310        InferBodyId::AnonConstId(_) => "{const}".to_owned(),
2311    };
2312    let _p = tracing::info_span!("mir_body_query", ?detail).entered();
2313    let (store, root_expr, self_param, params) = match def {
2314        InferBodyId::DefWithBodyId(def) => {
2315            let body = Body::of(db, def);
2316            (&**body, body.root_expr(), body.self_param.map(|param| param.formal), &*body.params)
2317        }
2318        InferBodyId::AnonConstId(def) => {
2319            let loc = def.loc(db);
2320            let store = ExpressionStore::of(db, loc.owner);
2321            (store, loc.expr, None, &[][..])
2322        }
2323    };
2324    let infer = InferenceResult::of(db, def);
2325    let mut result = lower_body_to_mir(db, def, store, infer, root_expr, self_param, params)?;
2326    result.shrink_to_fit();
2327    Ok(result)
2328}
2329
2330fn mir_body_cycle_result<'db>(
2331    _db: &'db dyn HirDatabase,
2332    _: salsa::Id,
2333    _def: InferBodyId<'db>,
2334) -> Result<'db, MirBody<'db>> {
2335    Err(MirLowerError::Loop)
2336}
2337
2338fn mir_body_for_closure_cycle_result<'db>(
2339    _db: &'db dyn HirDatabase,
2340    _: salsa::Id,
2341    _def: InternedClosureId<'db>,
2342) -> Result<'db, MirBody<'db>> {
2343    Err(MirLowerError::Loop)
2344}
2345
2346/// Extracts params from `body.params`/`body.self_param` and the callable signature,
2347/// then delegates to [`lower_to_mir_with_store`].
2348pub fn lower_body_to_mir<'db>(
2349    db: &'db dyn HirDatabase,
2350    owner: InferBodyId<'db>,
2351    store: &ExpressionStore,
2352    infer: &InferenceResult<'db>,
2353    root_expr: ExprId,
2354    self_param: Option<BindingId>,
2355    params: &[Param<PatId>],
2356) -> Result<'db, MirBody<'db>> {
2357    // Extract params and self_param only when lowering the body's root expression for a function.
2358    if let Some(fid) = owner.as_function() {
2359        let callable_sig = {
2360            let resolver = owner.resolver(db);
2361            let interner = DbInterner::new_with(db, resolver.krate());
2362            interner.liberate_late_bound_regions(
2363                fid.into(),
2364                db.callable_item_signature(fid.into()).instantiate_identity().skip_norm_wip(),
2365            )
2366        };
2367        let mut param_tys = callable_sig.inputs().iter().copied();
2368        let self_param = self_param.and_then(|id| Some((id, param_tys.next()?)));
2369
2370        lower_to_mir_with_store(
2371            db,
2372            owner,
2373            store,
2374            infer,
2375            root_expr,
2376            params.iter().map(|param| param.formal).zip(param_tys),
2377            self_param,
2378        )
2379    } else {
2380        lower_to_mir_with_store(db, owner, store, infer, root_expr, iter::empty(), None)
2381    }
2382}
2383
2384/// # Parameters
2385/// - `is_root`: `true` when `root_expr` is the body's top-level expression (picks
2386///   bindings with no owner); `false` when lowering an inline const or anonymous
2387///   const (picks bindings owned by `root_expr`).
2388pub fn lower_to_mir_with_store<'db>(
2389    db: &'db dyn HirDatabase,
2390    owner: InferBodyId<'db>,
2391    store: &ExpressionStore,
2392    infer: &InferenceResult<'db>,
2393    root_expr: ExprId,
2394    params: impl Iterator<Item = (PatId, Ty<'db>)> + Clone,
2395    self_param: Option<(BindingId, Ty<'db>)>,
2396) -> Result<'db, MirBody<'db>> {
2397    if infer.has_type_mismatches() || infer.is_erroneous() {
2398        return Err(MirLowerError::HasErrors);
2399    }
2400    let mut ctx = MirLowerCtx::new(db, owner, store, infer);
2401    // 0 is return local
2402    ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr).store() });
2403    let expected_binding_owner =
2404        if matches!(owner, InferBodyId::DefWithBodyId(_)) { None } else { Some(root_expr) };
2405    let binding_picker = |b: BindingId| ctx.store.binding_owner(b) == expected_binding_owner;
2406    let current = ctx.lower_params_and_bindings(params, self_param, binding_picker)?;
2407    if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? {
2408        let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?;
2409        ctx.set_terminator(current, TerminatorKind::Return, root_expr.into());
2410    }
2411    Ok(ctx.result)
2412}