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