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