1use 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 end: Option<BasicBlockId>,
64 place: Place,
65 drop_scope_index: usize,
66}
67
68#[derive(Debug, Clone, Default)]
69struct DropScope {
70 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#[derive(Debug, Clone, PartialEq, Eq)]
90pub enum MirLowerError {
91 ConstEvalError(Box<str>, Box<ConstEvalError>),
92 LayoutError(LayoutError),
93 IncompleteExpr,
94 IncompletePattern,
95 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 TypeError(&'static str),
107 NotSupported(String),
108 ContinueWithoutLoop,
109 BreakWithoutLoop,
110 Loop,
111 ImplementationError(String),
113 LangItemNotFound(LangItem),
114 MutatingRvalue,
115 UnresolvedLabel,
116 UnresolvedUpvar(Place),
117 InaccessibleLocal,
118
119 GenericArgNotProvided(TypeOrConstParamId, Substitution),
121}
122
123struct 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 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
150impl 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 return Ok(Some(current));
452 }
453 hir_def::AssocItemId::TypeAliasId(_) => {
454 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 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 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 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 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 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 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 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, 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!(), },
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 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), 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 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 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 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 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 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 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 fn pop_drop_scope_assume_dropped_internal(&mut self) {
1975 self.drop_scopes.pop();
1976 }
1977
1978 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 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 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 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 let current = 'b: {
2206 if body.body_expr == root_expr {
2207 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}