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