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