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