1use itertools::Itertools;
2use rustc_abi::{FIRST_VARIANT, FieldIdx, Size, VariantIdx};
3use rustc_ast::UnsafeBinderCastKind;
4use rustc_data_structures::stack::ensure_sufficient_stack;
5use rustc_hir as hir;
6use rustc_hir::attrs::AttributeKind;
7use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
8use rustc_hir::{LangItem, find_attr};
9use rustc_index::Idx;
10use rustc_middle::hir::place::{
11 Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
12};
13use rustc_middle::middle::region;
14use rustc_middle::mir::{self, AssignOp, BinOp, BorrowKind, UnOp};
15use rustc_middle::thir::*;
16use rustc_middle::ty::adjustment::{
17 Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCoercion,
18};
19use rustc_middle::ty::{
20 self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs,
21};
22use rustc_middle::{bug, span_bug};
23use rustc_span::{Span, sym};
24use tracing::{debug, info, instrument, trace};
25
26use crate::errors::*;
27use crate::thir::cx::ThirBuildCx;
28
29impl<'tcx> ThirBuildCx<'tcx> {
30 pub(crate) fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
39 ensure_sufficient_stack(|| self.mirror_expr_inner(expr))
41 }
42
43 pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
44 ensure_sufficient_stack(|| exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect())
48 }
49
50 #[instrument(level = "trace", skip(self, hir_expr))]
51 pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
52 let expr_scope =
53 region::Scope { local_id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
54
55 trace!(?hir_expr.hir_id, ?hir_expr.span);
56
57 let mut expr = self.make_mirror_unadjusted(hir_expr);
58
59 trace!(?expr.ty);
60
61 if self.apply_adjustments {
63 for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
64 trace!(?expr, ?adjustment);
65 let span = expr.span;
66 expr = self.apply_adjustment(hir_expr, expr, adjustment, span);
67 }
68 }
69
70 trace!(?expr.ty, "after adjustments");
71
72 expr = Expr {
74 temp_scope_id: expr_scope.local_id,
75 ty: expr.ty,
76 span: hir_expr.span,
77 kind: ExprKind::Scope {
78 region_scope: expr_scope,
79 value: self.thir.exprs.push(expr),
80 lint_level: LintLevel::Explicit(hir_expr.hir_id),
81 },
82 };
83
84 self.thir.exprs.push(expr)
86 }
87
88 #[instrument(level = "trace", skip(self, expr, span))]
89 fn apply_adjustment(
90 &mut self,
91 hir_expr: &'tcx hir::Expr<'tcx>,
92 mut expr: Expr<'tcx>,
93 adjustment: &Adjustment<'tcx>,
94 mut span: Span,
95 ) -> Expr<'tcx> {
96 let Expr { temp_scope_id, .. } = expr;
97
98 let mut adjust_span = |expr: &mut Expr<'tcx>| {
109 if let ExprKind::Block { block } = expr.kind
110 && let Some(last_expr) = self.thir[block].expr
111 {
112 span = self.thir[last_expr].span;
113 expr.span = span;
114 }
115 };
116
117 let kind = match adjustment.kind {
118 Adjust::Pointer(cast) => {
119 if cast == PointerCoercion::Unsize {
120 adjust_span(&mut expr);
121 }
122
123 let is_from_as_cast = if let hir::Node::Expr(hir::Expr {
124 kind: hir::ExprKind::Cast(..),
125 span: cast_span,
126 ..
127 }) = self.tcx.parent_hir_node(hir_expr.hir_id)
128 {
129 span = *cast_span;
131 true
132 } else {
133 false
134 };
135 ExprKind::PointerCoercion {
136 cast,
137 source: self.thir.exprs.push(expr),
138 is_from_as_cast,
139 }
140 }
141 Adjust::NeverToAny if adjustment.target.is_never() => return expr,
142 Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
143 Adjust::Deref(None) => {
144 adjust_span(&mut expr);
145 ExprKind::Deref { arg: self.thir.exprs.push(expr) }
146 }
147 Adjust::Deref(Some(deref)) => {
148 let call_def_id = deref.method_call(self.tcx);
151 let overloaded_callee =
152 Ty::new_fn_def(self.tcx, call_def_id, self.tcx.mk_args(&[expr.ty.into()]));
153
154 expr = Expr {
155 temp_scope_id,
156 ty: Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, expr.ty, deref.mutbl),
157 span,
158 kind: ExprKind::Borrow {
159 borrow_kind: deref.mutbl.to_borrow_kind(),
160 arg: self.thir.exprs.push(expr),
161 },
162 };
163
164 let expr = Box::new([self.thir.exprs.push(expr)]);
165
166 self.overloaded_place(
167 hir_expr,
168 adjustment.target,
169 Some(overloaded_callee),
170 expr,
171 deref.span,
172 )
173 }
174 Adjust::Borrow(AutoBorrow::Ref(m)) => ExprKind::Borrow {
175 borrow_kind: m.to_borrow_kind(),
176 arg: self.thir.exprs.push(expr),
177 },
178 Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
179 ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) }
180 }
181 Adjust::ReborrowPin(mutbl) => {
182 debug!("apply ReborrowPin adjustment");
183 let pin_ty_args = match expr.ty.kind() {
187 ty::Adt(_, args) => args,
188 _ => bug!("ReborrowPin with non-Pin type"),
189 };
190 let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty();
191 let ptr_target_ty = match pin_ty.kind() {
192 ty::Ref(_, ty, _) => *ty,
193 _ => bug!("ReborrowPin with non-Ref type"),
194 };
195
196 let pointer_target = ExprKind::Field {
198 lhs: self.thir.exprs.push(expr),
199 variant_index: FIRST_VARIANT,
200 name: FieldIdx::ZERO,
201 };
202 let arg = Expr { temp_scope_id, ty: pin_ty, span, kind: pointer_target };
203 let arg = self.thir.exprs.push(arg);
204
205 let expr = ExprKind::Deref { arg };
207 let arg = self.thir.exprs.push(Expr {
208 temp_scope_id,
209 ty: ptr_target_ty,
210 span,
211 kind: expr,
212 });
213
214 let borrow_kind = match mutbl {
216 hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
217 hir::Mutability::Not => BorrowKind::Shared,
218 };
219 let new_pin_target =
220 Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, ptr_target_ty, mutbl);
221 let expr = self.thir.exprs.push(Expr {
222 temp_scope_id,
223 ty: new_pin_target,
224 span,
225 kind: ExprKind::Borrow { borrow_kind, arg },
226 });
227
228 let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span);
230 let args = self.tcx.mk_args(&[new_pin_target.into()]);
231 let kind = ExprKind::Adt(Box::new(AdtExpr {
232 adt_def: self.tcx.adt_def(pin_did),
233 variant_index: FIRST_VARIANT,
234 args,
235 fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]),
236 user_ty: None,
237 base: AdtExprBase::None,
238 }));
239
240 debug!(?kind);
241 kind
242 }
243 };
244
245 Expr { temp_scope_id, ty: adjustment.target, span, kind }
246 }
247
248 fn mirror_expr_cast(
252 &mut self,
253 source: &'tcx hir::Expr<'tcx>,
254 temp_scope_id: hir::ItemLocalId,
255 span: Span,
256 ) -> ExprKind<'tcx> {
257 let tcx = self.tcx;
258
259 if self.typeck_results.is_coercion_cast(source.hir_id) {
262 ExprKind::Use { source: self.mirror_expr(source) }
264 } else if self.typeck_results.expr_ty(source).is_ref() {
265 ExprKind::PointerCoercion {
269 source: self.mirror_expr(source),
270 cast: PointerCoercion::ArrayToPointer,
271 is_from_as_cast: true,
272 }
273 } else if let hir::ExprKind::Path(ref qpath) = source.kind
274 && let res = self.typeck_results.qpath_res(qpath, source.hir_id)
275 && let ty = self.typeck_results.node_type(source.hir_id)
276 && let ty::Adt(adt_def, args) = ty.kind()
277 && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
278 {
279 let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
292 let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx);
293
294 use rustc_middle::ty::util::IntTypeExt;
295 let ty = adt_def.repr().discr_type();
296 let discr_ty = ty.to_ty(tcx);
297
298 let size = tcx
299 .layout_of(self.typing_env.as_query_input(discr_ty))
300 .unwrap_or_else(|e| panic!("could not compute layout for {discr_ty:?}: {e:?}"))
301 .size;
302
303 let (lit, overflowing) = ScalarInt::truncate_from_uint(discr_offset as u128, size);
304 if overflowing {
305 self.tcx.dcx().span_delayed_bug(
307 source.span,
308 "overflowing enum wasn't rejected by hir analysis",
309 );
310 }
311 let kind = ExprKind::NonHirLiteral { lit, user_ty: None };
312 let offset = self.thir.exprs.push(Expr { temp_scope_id, ty: discr_ty, span, kind });
313
314 let source = match discr_did {
315 Some(did) => {
318 let kind = ExprKind::NamedConst { def_id: did, args, user_ty: None };
319 let lhs =
320 self.thir.exprs.push(Expr { temp_scope_id, ty: discr_ty, span, kind });
321 let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
322 self.thir.exprs.push(Expr { temp_scope_id, ty: discr_ty, span, kind: bin })
323 }
324 None => offset,
325 };
326
327 ExprKind::Cast { source }
328 } else {
329 ExprKind::Cast { source: self.mirror_expr(source) }
332 }
333 }
334
335 #[instrument(level = "debug", skip(self), ret)]
336 fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
337 let tcx = self.tcx;
338 let expr_ty = self.typeck_results.expr_ty(expr);
339 let mk_expr =
340 |kind, ty| Expr { temp_scope_id: expr.hir_id.local_id, span: expr.span, ty, kind };
341
342 let kind = match expr.kind {
343 hir::ExprKind::MethodCall(segment, receiver, args, fn_span) => {
345 let expr = self.method_callee(expr, segment.ident.span, None);
347 info!("Using method span: {:?}", expr.span);
348 let args = std::iter::once(receiver)
349 .chain(args.iter())
350 .map(|expr| self.mirror_expr(expr))
351 .collect();
352 ExprKind::Call {
353 ty: expr.ty,
354 fun: self.thir.exprs.push(expr),
355 args,
356 from_hir_call: true,
357 fn_span,
358 }
359 }
360
361 hir::ExprKind::Call(fun, ref args) => {
362 if self.typeck_results.is_method_call(expr) {
363 let method = self.method_callee(expr, fun.span, None);
371
372 let arg_tys = args.iter().map(|e| self.typeck_results.expr_ty_adjusted(e));
373 let tupled_args = Expr {
374 ty: Ty::new_tup_from_iter(tcx, arg_tys),
375 temp_scope_id: expr.hir_id.local_id,
376 span: expr.span,
377 kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
378 };
379 let tupled_args = self.thir.exprs.push(tupled_args);
380
381 ExprKind::Call {
382 ty: method.ty,
383 fun: self.thir.exprs.push(method),
384 args: Box::new([self.mirror_expr(fun), tupled_args]),
385 from_hir_call: true,
386 fn_span: expr.span,
387 }
388 } else if let ty::FnDef(def_id, _) = self.typeck_results.expr_ty(fun).kind()
389 && let Some(intrinsic) = self.tcx.intrinsic(def_id)
390 && intrinsic.name == sym::box_new
391 {
392 if !matches!(fun.kind, hir::ExprKind::Path(_)) {
394 span_bug!(
395 expr.span,
396 "`box_new` intrinsic can only be called via path expression"
397 );
398 }
399 let value = &args[0];
400 return Expr {
401 temp_scope_id: expr.hir_id.local_id,
402 ty: expr_ty,
403 span: expr.span,
404 kind: ExprKind::Box { value: self.mirror_expr(value) },
405 };
406 } else {
407 let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind
409 && let Some(adt_def) = expr_ty.ty_adt_def()
410 {
411 match qpath {
412 hir::QPath::Resolved(_, path) => match path.res {
413 Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
414 Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
415 }
416 Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)),
417 _ => None,
418 },
419 hir::QPath::TypeRelative(_ty, _) => {
420 if let Some((DefKind::Ctor(_, CtorKind::Fn), ctor_id)) =
421 self.typeck_results.type_dependent_def(fun.hir_id)
422 {
423 Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
424 } else {
425 None
426 }
427 }
428 }
429 } else {
430 None
431 };
432 if let Some((adt_def, index)) = adt_data {
433 let node_args = self.typeck_results.node_args(fun.hir_id);
434 let user_provided_types = self.typeck_results.user_provided_types();
435 let user_ty =
436 user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| {
437 if let ty::UserTypeKind::TypeOf(did, _) = &mut u_ty.value.kind {
438 *did = adt_def.did();
439 }
440 Box::new(u_ty)
441 });
442 debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
443
444 let field_refs = args
445 .iter()
446 .enumerate()
447 .map(|(idx, e)| FieldExpr {
448 name: FieldIdx::new(idx),
449 expr: self.mirror_expr(e),
450 })
451 .collect();
452 ExprKind::Adt(Box::new(AdtExpr {
453 adt_def,
454 args: node_args,
455 variant_index: index,
456 fields: field_refs,
457 user_ty,
458 base: AdtExprBase::None,
459 }))
460 } else {
461 ExprKind::Call {
462 ty: self.typeck_results.node_type(fun.hir_id),
463 fun: self.mirror_expr(fun),
464 args: self.mirror_exprs(args),
465 from_hir_call: true,
466 fn_span: expr.span,
467 }
468 }
469 }
470 }
471
472 hir::ExprKind::Use(expr, span) => {
473 ExprKind::ByUse { expr: self.mirror_expr(expr), span }
474 }
475
476 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => {
477 ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
478 }
479
480 hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, arg) => {
481 ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
482 }
483
484 hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() {
487 &ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => {
488 let ty = args.type_at(0);
489 let arg_ty = self.typeck_results.expr_ty(arg_expr);
490 let mut arg = self.mirror_expr(arg_expr);
491 if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) {
494 let block = self.thir.blocks.push(Block {
495 targeted_by_break: false,
496 region_scope: region::Scope {
497 local_id: arg_expr.hir_id.local_id,
498 data: region::ScopeData::Node,
499 },
500 span: arg_expr.span,
501 stmts: Box::new([]),
502 expr: Some(arg),
503 safety_mode: BlockSafety::Safe,
504 });
505 arg = self.thir.exprs.push(Expr {
506 temp_scope_id: arg_expr.hir_id.local_id,
507 ty: arg_ty,
508 span: arg_expr.span,
509 kind: ExprKind::Block { block },
510 });
511 }
512 let expr = self.thir.exprs.push(Expr {
513 temp_scope_id: expr.hir_id.local_id,
514 ty,
515 span: expr.span,
516 kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
517 });
518 ExprKind::Adt(Box::new(AdtExpr {
519 adt_def,
520 variant_index: FIRST_VARIANT,
521 args,
522 fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
523 user_ty: None,
524 base: AdtExprBase::None,
525 }))
526 }
527 _ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty),
528 },
529
530 hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
531
532 hir::ExprKind::Assign(lhs, rhs, _) => {
533 ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) }
534 }
535
536 hir::ExprKind::AssignOp(op, lhs, rhs) => {
537 if self.typeck_results.is_method_call(expr) {
538 let lhs = self.mirror_expr(lhs);
539 let rhs = self.mirror_expr(rhs);
540 self.overloaded_operator(expr, Box::new([lhs, rhs]))
541 } else {
542 ExprKind::AssignOp {
543 op: assign_op(op.node),
544 lhs: self.mirror_expr(lhs),
545 rhs: self.mirror_expr(rhs),
546 }
547 }
548 }
549
550 hir::ExprKind::Lit(lit) => ExprKind::Literal { lit, neg: false },
551
552 hir::ExprKind::Binary(op, lhs, rhs) => {
553 if self.typeck_results.is_method_call(expr) {
554 let lhs = self.mirror_expr(lhs);
555 let rhs = self.mirror_expr(rhs);
556 self.overloaded_operator(expr, Box::new([lhs, rhs]))
557 } else {
558 match op.node {
559 hir::BinOpKind::And => ExprKind::LogicalOp {
560 op: LogicalOp::And,
561 lhs: self.mirror_expr(lhs),
562 rhs: self.mirror_expr(rhs),
563 },
564 hir::BinOpKind::Or => ExprKind::LogicalOp {
565 op: LogicalOp::Or,
566 lhs: self.mirror_expr(lhs),
567 rhs: self.mirror_expr(rhs),
568 },
569 _ => {
570 let op = bin_op(op.node);
571 ExprKind::Binary {
572 op,
573 lhs: self.mirror_expr(lhs),
574 rhs: self.mirror_expr(rhs),
575 }
576 }
577 }
578 }
579 }
580
581 hir::ExprKind::Index(lhs, index, brackets_span) => {
582 if self.typeck_results.is_method_call(expr) {
583 let lhs = self.mirror_expr(lhs);
584 let index = self.mirror_expr(index);
585 self.overloaded_place(
586 expr,
587 expr_ty,
588 None,
589 Box::new([lhs, index]),
590 brackets_span,
591 )
592 } else {
593 ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
594 }
595 }
596
597 hir::ExprKind::Unary(hir::UnOp::Deref, arg) => {
598 if self.typeck_results.is_method_call(expr) {
599 let arg = self.mirror_expr(arg);
600 self.overloaded_place(expr, expr_ty, None, Box::new([arg]), expr.span)
601 } else {
602 ExprKind::Deref { arg: self.mirror_expr(arg) }
603 }
604 }
605
606 hir::ExprKind::Unary(hir::UnOp::Not, arg) => {
607 if self.typeck_results.is_method_call(expr) {
608 let arg = self.mirror_expr(arg);
609 self.overloaded_operator(expr, Box::new([arg]))
610 } else {
611 ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) }
612 }
613 }
614
615 hir::ExprKind::Unary(hir::UnOp::Neg, arg) => {
616 if self.typeck_results.is_method_call(expr) {
617 let arg = self.mirror_expr(arg);
618 self.overloaded_operator(expr, Box::new([arg]))
619 } else if let hir::ExprKind::Lit(lit) = arg.kind {
620 ExprKind::Literal { lit, neg: true }
621 } else {
622 ExprKind::Unary { op: UnOp::Neg, arg: self.mirror_expr(arg) }
623 }
624 }
625
626 hir::ExprKind::Struct(qpath, fields, ref base) => match expr_ty.kind() {
627 ty::Adt(adt, args) => match adt.adt_kind() {
628 AdtKind::Struct | AdtKind::Union => {
629 let user_provided_types = self.typeck_results.user_provided_types();
630 let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new);
631 debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
632 ExprKind::Adt(Box::new(AdtExpr {
633 adt_def: *adt,
634 variant_index: FIRST_VARIANT,
635 args,
636 user_ty,
637 fields: self.field_refs(fields),
638 base: match base {
639 hir::StructTailExpr::Base(base) => AdtExprBase::Base(FruInfo {
640 base: self.mirror_expr(base),
641 field_types: self.typeck_results.fru_field_types()[expr.hir_id]
642 .iter()
643 .copied()
644 .collect(),
645 }),
646 hir::StructTailExpr::DefaultFields(_) => {
647 AdtExprBase::DefaultFields(
648 self.typeck_results.fru_field_types()[expr.hir_id]
649 .iter()
650 .copied()
651 .collect(),
652 )
653 }
654 hir::StructTailExpr::None => AdtExprBase::None,
655 },
656 }))
657 }
658 AdtKind::Enum => {
659 let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
660 match res {
661 Res::Def(DefKind::Variant, variant_id) => {
662 assert!(matches!(
663 base,
664 hir::StructTailExpr::None
665 | hir::StructTailExpr::DefaultFields(_)
666 ));
667
668 let index = adt.variant_index_with_id(variant_id);
669 let user_provided_types = self.typeck_results.user_provided_types();
670 let user_ty =
671 user_provided_types.get(expr.hir_id).copied().map(Box::new);
672 debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
673 ExprKind::Adt(Box::new(AdtExpr {
674 adt_def: *adt,
675 variant_index: index,
676 args,
677 user_ty,
678 fields: self.field_refs(fields),
679 base: match base {
680 hir::StructTailExpr::DefaultFields(_) => {
681 AdtExprBase::DefaultFields(
682 self.typeck_results.fru_field_types()[expr.hir_id]
683 .iter()
684 .copied()
685 .collect(),
686 )
687 }
688 hir::StructTailExpr::Base(base) => {
689 span_bug!(base.span, "unexpected res: {:?}", res);
690 }
691 hir::StructTailExpr::None => AdtExprBase::None,
692 },
693 }))
694 }
695 _ => {
696 span_bug!(expr.span, "unexpected res: {:?}", res);
697 }
698 }
699 }
700 },
701 _ => {
702 span_bug!(expr.span, "unexpected type for struct literal: {:?}", expr_ty);
703 }
704 },
705
706 hir::ExprKind::Closure(hir::Closure { .. }) => {
707 let closure_ty = self.typeck_results.expr_ty(expr);
708 let (def_id, args, movability) = match *closure_ty.kind() {
709 ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
710 ty::Coroutine(def_id, args) => {
711 (def_id, UpvarArgs::Coroutine(args), Some(tcx.coroutine_movability(def_id)))
712 }
713 ty::CoroutineClosure(def_id, args) => {
714 (def_id, UpvarArgs::CoroutineClosure(args), None)
715 }
716 _ => {
717 span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
718 }
719 };
720 let def_id = def_id.expect_local();
721
722 let upvars = self
723 .tcx
724 .closure_captures(def_id)
725 .iter()
726 .zip_eq(args.upvar_tys())
727 .map(|(captured_place, ty)| {
728 let upvars = self.capture_upvar(expr, captured_place, ty);
729 self.thir.exprs.push(upvars)
730 })
731 .collect();
732
733 let fake_reads = match self.typeck_results.closure_fake_reads.get(&def_id) {
735 Some(fake_reads) => fake_reads
736 .iter()
737 .map(|(place, cause, hir_id)| {
738 let expr = self.convert_captured_hir_place(expr, place.clone());
739 (self.thir.exprs.push(expr), *cause, *hir_id)
740 })
741 .collect(),
742 None => Vec::new(),
743 };
744
745 ExprKind::Closure(Box::new(ClosureExpr {
746 closure_id: def_id,
747 args,
748 upvars,
749 movability,
750 fake_reads,
751 }))
752 }
753
754 hir::ExprKind::Path(ref qpath) => {
755 let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
756 self.convert_path_expr(expr, res)
757 }
758
759 hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr {
760 asm_macro: asm.asm_macro,
761 template: asm.template,
762 operands: asm
763 .operands
764 .iter()
765 .map(|(op, _op_sp)| match *op {
766 hir::InlineAsmOperand::In { reg, expr } => {
767 InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
768 }
769 hir::InlineAsmOperand::Out { reg, late, ref expr } => {
770 InlineAsmOperand::Out {
771 reg,
772 late,
773 expr: expr.map(|expr| self.mirror_expr(expr)),
774 }
775 }
776 hir::InlineAsmOperand::InOut { reg, late, expr } => {
777 InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
778 }
779 hir::InlineAsmOperand::SplitInOut { reg, late, in_expr, ref out_expr } => {
780 InlineAsmOperand::SplitInOut {
781 reg,
782 late,
783 in_expr: self.mirror_expr(in_expr),
784 out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
785 }
786 }
787 hir::InlineAsmOperand::Const { ref anon_const } => {
788 let ty = self.typeck_results.node_type(anon_const.hir_id);
789 let did = anon_const.def_id.to_def_id();
790 let typeck_root_def_id = tcx.typeck_root_def_id(did);
791 let parent_args = tcx.erase_and_anonymize_regions(
792 GenericArgs::identity_for_item(tcx, typeck_root_def_id),
793 );
794 let args =
795 InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty })
796 .args;
797
798 let uneval = mir::UnevaluatedConst::new(did, args);
799 let value = mir::Const::Unevaluated(uneval, ty);
800 InlineAsmOperand::Const { value, span: tcx.def_span(did) }
801 }
802 hir::InlineAsmOperand::SymFn { expr } => {
803 InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }
804 }
805 hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
806 InlineAsmOperand::SymStatic { def_id }
807 }
808 hir::InlineAsmOperand::Label { block } => {
809 InlineAsmOperand::Label { block: self.mirror_block(block) }
810 }
811 })
812 .collect(),
813 options: asm.options,
814 line_spans: asm.line_spans,
815 })),
816
817 hir::ExprKind::OffsetOf(_, _) => {
818 let offset_of_intrinsic = tcx.require_lang_item(LangItem::OffsetOf, expr.span);
819 let mk_u32_kind = |val: u32| ExprKind::NonHirLiteral {
820 lit: ScalarInt::try_from_uint(val, Size::from_bits(32)).unwrap(),
821 user_ty: None,
822 };
823 let mk_call =
824 |thir: &mut Thir<'tcx>, ty: Ty<'tcx>, variant: VariantIdx, field: FieldIdx| {
825 let fun_ty =
826 Ty::new_fn_def(tcx, offset_of_intrinsic, [ty::GenericArg::from(ty)]);
827 let fun = thir
828 .exprs
829 .push(mk_expr(ExprKind::ZstLiteral { user_ty: None }, fun_ty));
830 let variant =
831 thir.exprs.push(mk_expr(mk_u32_kind(variant.as_u32()), tcx.types.u32));
832 let field =
833 thir.exprs.push(mk_expr(mk_u32_kind(field.as_u32()), tcx.types.u32));
834 let args = Box::new([variant, field]);
835 ExprKind::Call {
836 ty: fun_ty,
837 fun,
838 args,
839 from_hir_call: false,
840 fn_span: expr.span,
841 }
842 };
843
844 let indices = self.typeck_results.offset_of_data().get(expr.hir_id).unwrap();
845 let mut expr = None::<ExprKind<'tcx>>;
846
847 for &(container, variant, field) in indices.iter() {
848 let next = mk_call(&mut self.thir, container, variant, field);
849 expr = Some(match expr.take() {
850 None => next,
851 Some(last) => {
852 let last = self.thir.exprs.push(mk_expr(last, tcx.types.usize));
853 let next = self.thir.exprs.push(mk_expr(next, tcx.types.usize));
854 ExprKind::Binary { op: BinOp::Add, lhs: last, rhs: next }
855 }
856 });
857 }
858
859 expr.unwrap_or(mk_u32_kind(0))
860 }
861
862 hir::ExprKind::ConstBlock(ref anon_const) => {
863 let ty = self.typeck_results.node_type(anon_const.hir_id);
864 let did = anon_const.def_id.to_def_id();
865 let typeck_root_def_id = tcx.typeck_root_def_id(did);
866 let parent_args = tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item(
867 tcx,
868 typeck_root_def_id,
869 ));
870 let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }).args;
871
872 ExprKind::ConstBlock { did, args }
873 }
874 hir::ExprKind::Repeat(v, _) => {
876 let ty = self.typeck_results.expr_ty(expr);
877 let ty::Array(_, count) = ty.kind() else {
878 span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty);
879 };
880
881 ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
882 }
883 hir::ExprKind::Ret(v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
884 hir::ExprKind::Become(call) => ExprKind::Become { value: self.mirror_expr(call) },
885 hir::ExprKind::Break(dest, ref value) => {
886 if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::ConstContinue(_)) {
887 match dest.target_id {
888 Ok(target_id) => {
889 let (Some(value), Some(_)) = (value, dest.label) else {
890 let span = expr.span;
891 self.tcx.dcx().emit_fatal(ConstContinueMissingLabelOrValue { span })
892 };
893
894 ExprKind::ConstContinue {
895 label: region::Scope {
896 local_id: target_id.local_id,
897 data: region::ScopeData::Node,
898 },
899 value: self.mirror_expr(value),
900 }
901 }
902 Err(err) => bug!("invalid loop id for break: {}", err),
903 }
904 } else {
905 match dest.target_id {
906 Ok(target_id) => ExprKind::Break {
907 label: region::Scope {
908 local_id: target_id.local_id,
909 data: region::ScopeData::Node,
910 },
911 value: value.map(|value| self.mirror_expr(value)),
912 },
913 Err(err) => bug!("invalid loop id for break: {}", err),
914 }
915 }
916 }
917 hir::ExprKind::Continue(dest) => match dest.target_id {
918 Ok(loop_id) => ExprKind::Continue {
919 label: region::Scope {
920 local_id: loop_id.local_id,
921 data: region::ScopeData::Node,
922 },
923 },
924 Err(err) => bug!("invalid loop id for continue: {}", err),
925 },
926 hir::ExprKind::Let(let_expr) => ExprKind::Let {
927 expr: self.mirror_expr(let_expr.init),
928 pat: self.pattern_from_hir(let_expr.pat),
929 },
930 hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
931 if_then_scope: region::Scope {
932 local_id: then.hir_id.local_id,
933 data: {
934 if expr.span.at_least_rust_2024() {
935 region::ScopeData::IfThenRescope
936 } else {
937 region::ScopeData::IfThen
938 }
939 },
940 },
941 cond: self.mirror_expr(cond),
942 then: self.mirror_expr(then),
943 else_opt: else_opt.map(|el| self.mirror_expr(el)),
944 },
945 hir::ExprKind::Match(discr, arms, match_source) => ExprKind::Match {
946 scrutinee: self.mirror_expr(discr),
947 arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
948 match_source,
949 },
950 hir::ExprKind::Loop(body, ..) => {
951 if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::LoopMatch(_)) {
952 let dcx = self.tcx.dcx();
953
954 let loop_body_expr = match body.stmts {
956 [] => match body.expr {
957 Some(expr) => expr,
958 None => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }),
959 },
960 [single] if body.expr.is_none() => match single.kind {
961 hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => expr,
962 _ => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }),
963 },
964 [first @ last] | [first, .., last] => dcx
965 .emit_fatal(LoopMatchBadStatements { span: first.span.to(last.span) }),
966 };
967
968 let hir::ExprKind::Assign(state, rhs_expr, _) = loop_body_expr.kind else {
969 dcx.emit_fatal(LoopMatchMissingAssignment { span: loop_body_expr.span })
970 };
971
972 let hir::ExprKind::Block(block_body, _) = rhs_expr.kind else {
973 dcx.emit_fatal(LoopMatchBadRhs { span: rhs_expr.span })
974 };
975
976 for stmt in block_body.stmts {
979 if !matches!(stmt.kind, rustc_hir::StmtKind::Item(_)) {
980 dcx.emit_fatal(LoopMatchBadStatements { span: stmt.span })
981 }
982 }
983
984 let Some(block_body_expr) = block_body.expr else {
985 dcx.emit_fatal(LoopMatchBadRhs { span: block_body.span })
986 };
987
988 let hir::ExprKind::Match(scrutinee, arms, _match_source) = block_body_expr.kind
989 else {
990 dcx.emit_fatal(LoopMatchBadRhs { span: block_body_expr.span })
991 };
992
993 fn local(
994 cx: &mut ThirBuildCx<'_>,
995 expr: &rustc_hir::Expr<'_>,
996 ) -> Option<hir::HirId> {
997 if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
998 && let Res::Local(hir_id) = path.res
999 && !cx.is_upvar(hir_id)
1000 {
1001 return Some(hir_id);
1002 }
1003
1004 None
1005 }
1006
1007 let Some(scrutinee_hir_id) = local(self, scrutinee) else {
1008 dcx.emit_fatal(LoopMatchInvalidMatch { span: scrutinee.span })
1009 };
1010
1011 if local(self, state) != Some(scrutinee_hir_id) {
1012 dcx.emit_fatal(LoopMatchInvalidUpdate {
1013 scrutinee: scrutinee.span,
1014 lhs: state.span,
1015 })
1016 }
1017
1018 ExprKind::LoopMatch {
1019 state: self.mirror_expr(state),
1020 region_scope: region::Scope {
1021 local_id: block_body.hir_id.local_id,
1022 data: region::ScopeData::Node,
1023 },
1024
1025 match_data: Box::new(LoopMatchMatchData {
1026 scrutinee: self.mirror_expr(scrutinee),
1027 arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
1028 span: block_body_expr.span,
1029 }),
1030 }
1031 } else {
1032 let block_ty = self.typeck_results.node_type(body.hir_id);
1033 let block = self.mirror_block(body);
1034 let body = self.thir.exprs.push(Expr {
1035 ty: block_ty,
1036 temp_scope_id: body.hir_id.local_id,
1037 span: self.thir[block].span,
1038 kind: ExprKind::Block { block },
1039 });
1040 ExprKind::Loop { body }
1041 }
1042 }
1043 hir::ExprKind::Field(source, ..) => ExprKind::Field {
1044 lhs: self.mirror_expr(source),
1045 variant_index: FIRST_VARIANT,
1046 name: self.typeck_results.field_index(expr.hir_id),
1047 },
1048 hir::ExprKind::Cast(source, cast_ty) => {
1049 let user_provided_types = self.typeck_results.user_provided_types();
1051 let user_ty = user_provided_types.get(cast_ty.hir_id);
1052
1053 debug!(
1054 "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
1055 expr, cast_ty.hir_id, user_ty,
1056 );
1057
1058 let cast = self.mirror_expr_cast(source, expr.hir_id.local_id, expr.span);
1059
1060 if let Some(user_ty) = user_ty {
1061 let cast_expr = self.thir.exprs.push(Expr {
1064 temp_scope_id: expr.hir_id.local_id,
1065 ty: expr_ty,
1066 span: expr.span,
1067 kind: cast,
1068 });
1069 debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
1070
1071 ExprKind::ValueTypeAscription {
1072 source: cast_expr,
1073 user_ty: Some(Box::new(*user_ty)),
1074 user_ty_span: cast_ty.span,
1075 }
1076 } else {
1077 cast
1078 }
1079 }
1080 hir::ExprKind::Type(source, ty) => {
1081 let user_provided_types = self.typeck_results.user_provided_types();
1082 let user_ty = user_provided_types.get(ty.hir_id).copied().map(Box::new);
1083 debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
1084 let mirrored = self.mirror_expr(source);
1085 if source.is_syntactic_place_expr() {
1086 ExprKind::PlaceTypeAscription {
1087 source: mirrored,
1088 user_ty,
1089 user_ty_span: ty.span,
1090 }
1091 } else {
1092 ExprKind::ValueTypeAscription {
1093 source: mirrored,
1094 user_ty,
1095 user_ty_span: ty.span,
1096 }
1097 }
1098 }
1099
1100 hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, source, _ty) => {
1101 let mirrored = self.mirror_expr(source);
1103 if source.is_syntactic_place_expr() {
1104 ExprKind::PlaceUnwrapUnsafeBinder { source: mirrored }
1105 } else {
1106 ExprKind::ValueUnwrapUnsafeBinder { source: mirrored }
1107 }
1108 }
1109 hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, source, _ty) => {
1110 let mirrored = self.mirror_expr(source);
1112 ExprKind::WrapUnsafeBinder { source: mirrored }
1113 }
1114
1115 hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
1116 hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
1117 hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
1118
1119 hir::ExprKind::Yield(v, _) => ExprKind::Yield { value: self.mirror_expr(v) },
1120 hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"),
1121 };
1122
1123 mk_expr(kind, expr_ty)
1124 }
1125
1126 fn user_args_applied_to_res(
1127 &mut self,
1128 hir_id: hir::HirId,
1129 res: Res,
1130 ) -> Option<Box<ty::CanonicalUserType<'tcx>>> {
1131 debug!("user_args_applied_to_res: res={:?}", res);
1132 let user_provided_type = match res {
1133 Res::Def(DefKind::Fn, _)
1137 | Res::Def(DefKind::AssocFn, _)
1138 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
1139 | Res::Def(DefKind::Const, _)
1140 | Res::Def(DefKind::AssocConst, _) => {
1141 self.typeck_results.user_provided_types().get(hir_id).copied().map(Box::new)
1142 }
1143
1144 Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
1149 self.user_args_applied_to_ty_of_hir_id(hir_id).map(Box::new)
1150 }
1151
1152 Res::SelfCtor(_) => self.user_args_applied_to_ty_of_hir_id(hir_id).map(Box::new),
1154
1155 _ => bug!("user_args_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
1156 };
1157 debug!("user_args_applied_to_res: user_provided_type={:?}", user_provided_type);
1158 user_provided_type
1159 }
1160
1161 fn method_callee(
1162 &mut self,
1163 expr: &hir::Expr<'_>,
1164 span: Span,
1165 overloaded_callee: Option<Ty<'tcx>>,
1166 ) -> Expr<'tcx> {
1167 let (ty, user_ty) = match overloaded_callee {
1168 Some(fn_def) => (fn_def, None),
1169 None => {
1170 let (kind, def_id) =
1171 self.typeck_results.type_dependent_def(expr.hir_id).unwrap_or_else(|| {
1172 span_bug!(expr.span, "no type-dependent def for method callee")
1173 });
1174 let user_ty = self.user_args_applied_to_res(expr.hir_id, Res::Def(kind, def_id));
1175 debug!("method_callee: user_ty={:?}", user_ty);
1176 (
1177 Ty::new_fn_def(self.tcx, def_id, self.typeck_results.node_args(expr.hir_id)),
1178 user_ty,
1179 )
1180 }
1181 };
1182 Expr {
1183 temp_scope_id: expr.hir_id.local_id,
1184 ty,
1185 span,
1186 kind: ExprKind::ZstLiteral { user_ty },
1187 }
1188 }
1189
1190 fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
1191 let arm = Arm {
1192 pattern: self.pattern_from_hir(&arm.pat),
1193 guard: arm.guard.as_ref().map(|g| self.mirror_expr(g)),
1194 body: self.mirror_expr(arm.body),
1195 lint_level: LintLevel::Explicit(arm.hir_id),
1196 scope: region::Scope { local_id: arm.hir_id.local_id, data: region::ScopeData::Node },
1197 span: arm.span,
1198 };
1199 self.thir.arms.push(arm)
1200 }
1201
1202 fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> {
1203 let args = self.typeck_results.node_args(expr.hir_id);
1204 match res {
1205 Res::Def(DefKind::Fn, _)
1207 | Res::Def(DefKind::AssocFn, _)
1208 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
1209 | Res::SelfCtor(_) => {
1210 let user_ty = self.user_args_applied_to_res(expr.hir_id, res);
1211 ExprKind::ZstLiteral { user_ty }
1212 }
1213
1214 Res::Def(DefKind::ConstParam, def_id) => {
1215 let hir_id = self.tcx.local_def_id_to_hir_id(def_id.expect_local());
1216 let generics = self.tcx.generics_of(hir_id.owner);
1217 let Some(&index) = generics.param_def_id_to_index.get(&def_id) else {
1218 span_bug!(
1219 expr.span,
1220 "Should have already errored about late bound consts: {def_id:?}"
1221 );
1222 };
1223 let name = self.tcx.hir_name(hir_id);
1224 let param = ty::ParamConst::new(index, name);
1225
1226 ExprKind::ConstParam { param, def_id }
1227 }
1228
1229 Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
1230 let user_ty = self.user_args_applied_to_res(expr.hir_id, res);
1231 ExprKind::NamedConst { def_id, args, user_ty }
1232 }
1233
1234 Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => {
1235 let user_provided_types = self.typeck_results.user_provided_types();
1236 let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new);
1237 debug!("convert_path_expr: user_ty={:?}", user_ty);
1238 let ty = self.typeck_results.node_type(expr.hir_id);
1239 match ty.kind() {
1240 ty::Adt(adt_def, args) => ExprKind::Adt(Box::new(AdtExpr {
1243 adt_def: *adt_def,
1244 variant_index: adt_def.variant_index_with_ctor_id(def_id),
1245 args,
1246 user_ty,
1247 fields: Box::new([]),
1248 base: AdtExprBase::None,
1249 })),
1250 _ => bug!("unexpected ty: {:?}", ty),
1251 }
1252 }
1253
1254 Res::Def(DefKind::Static { .. }, id) => {
1258 let ty = self.tcx.static_ptr_ty(id, self.typing_env);
1260 let kind = if self.tcx.is_thread_local_static(id) {
1261 ExprKind::ThreadLocalRef(id)
1262 } else {
1263 let alloc_id = self.tcx.reserve_and_set_static_alloc(id);
1264 ExprKind::StaticRef { alloc_id, ty, def_id: id }
1265 };
1266 ExprKind::Deref {
1267 arg: self.thir.exprs.push(Expr {
1268 ty,
1269 temp_scope_id: expr.hir_id.local_id,
1270 span: expr.span,
1271 kind,
1272 }),
1273 }
1274 }
1275
1276 Res::Local(var_hir_id) => self.convert_var(var_hir_id),
1277
1278 _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
1279 }
1280 }
1281
1282 fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
1283 let is_upvar = self.is_upvar(var_hir_id);
1286
1287 debug!(
1288 "convert_var({:?}): is_upvar={}, body_owner={:?}",
1289 var_hir_id, is_upvar, self.body_owner
1290 );
1291
1292 if is_upvar {
1293 ExprKind::UpvarRef {
1294 closure_def_id: self.body_owner,
1295 var_hir_id: LocalVarId(var_hir_id),
1296 }
1297 } else {
1298 ExprKind::VarRef { id: LocalVarId(var_hir_id) }
1299 }
1300 }
1301
1302 fn overloaded_operator(
1303 &mut self,
1304 expr: &'tcx hir::Expr<'tcx>,
1305 args: Box<[ExprId]>,
1306 ) -> ExprKind<'tcx> {
1307 let fun = self.method_callee(expr, expr.span, None);
1308 let fun = self.thir.exprs.push(fun);
1309 ExprKind::Call {
1310 ty: self.thir[fun].ty,
1311 fun,
1312 args,
1313 from_hir_call: false,
1314 fn_span: expr.span,
1315 }
1316 }
1317
1318 fn overloaded_place(
1319 &mut self,
1320 expr: &'tcx hir::Expr<'tcx>,
1321 place_ty: Ty<'tcx>,
1322 overloaded_callee: Option<Ty<'tcx>>,
1323 args: Box<[ExprId]>,
1324 span: Span,
1325 ) -> ExprKind<'tcx> {
1326 let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
1334 span_bug!(span, "overloaded_place: receiver is not a reference");
1335 };
1336 let ref_ty = Ty::new_ref(self.tcx, region, place_ty, mutbl);
1337
1338 let fun = self.method_callee(expr, span, overloaded_callee);
1341 let fun = self.thir.exprs.push(fun);
1342 let fun_ty = self.thir[fun].ty;
1343 let ref_expr = self.thir.exprs.push(Expr {
1344 temp_scope_id: expr.hir_id.local_id,
1345 ty: ref_ty,
1346 span,
1347 kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span },
1348 });
1349
1350 ExprKind::Deref { arg: ref_expr }
1352 }
1353
1354 fn convert_captured_hir_place(
1355 &mut self,
1356 closure_expr: &'tcx hir::Expr<'tcx>,
1357 place: HirPlace<'tcx>,
1358 ) -> Expr<'tcx> {
1359 let temp_scope_id = closure_expr.hir_id.local_id;
1360 let var_ty = place.base_ty;
1361
1362 let var_hir_id = match place.base {
1368 HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
1369 base => bug!("Expected an upvar, found {:?}", base),
1370 };
1371
1372 let mut captured_place_expr = Expr {
1373 temp_scope_id,
1374 ty: var_ty,
1375 span: closure_expr.span,
1376 kind: self.convert_var(var_hir_id),
1377 };
1378
1379 for proj in place.projections.iter() {
1380 let kind = match proj.kind {
1381 HirProjectionKind::Deref => {
1382 ExprKind::Deref { arg: self.thir.exprs.push(captured_place_expr) }
1383 }
1384 HirProjectionKind::Field(field, variant_index) => ExprKind::Field {
1385 lhs: self.thir.exprs.push(captured_place_expr),
1386 variant_index,
1387 name: field,
1388 },
1389 HirProjectionKind::OpaqueCast => {
1390 ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) }
1391 }
1392 HirProjectionKind::UnwrapUnsafeBinder => ExprKind::PlaceUnwrapUnsafeBinder {
1393 source: self.thir.exprs.push(captured_place_expr),
1394 },
1395 HirProjectionKind::Index | HirProjectionKind::Subslice => {
1396 continue;
1398 }
1399 };
1400
1401 captured_place_expr =
1402 Expr { temp_scope_id, ty: proj.ty, span: closure_expr.span, kind };
1403 }
1404
1405 captured_place_expr
1406 }
1407
1408 fn capture_upvar(
1409 &mut self,
1410 closure_expr: &'tcx hir::Expr<'tcx>,
1411 captured_place: &'tcx ty::CapturedPlace<'tcx>,
1412 upvar_ty: Ty<'tcx>,
1413 ) -> Expr<'tcx> {
1414 let upvar_capture = captured_place.info.capture_kind;
1415 let captured_place_expr =
1416 self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
1417 let temp_scope_id = closure_expr.hir_id.local_id;
1418
1419 match upvar_capture {
1420 ty::UpvarCapture::ByValue => captured_place_expr,
1421 ty::UpvarCapture::ByUse => {
1422 let span = captured_place_expr.span;
1423 let expr_id = self.thir.exprs.push(captured_place_expr);
1424
1425 Expr {
1426 temp_scope_id,
1427 ty: upvar_ty,
1428 span: closure_expr.span,
1429 kind: ExprKind::ByUse { expr: expr_id, span },
1430 }
1431 }
1432 ty::UpvarCapture::ByRef(upvar_borrow) => {
1433 let borrow_kind = match upvar_borrow {
1434 ty::BorrowKind::Immutable => BorrowKind::Shared,
1435 ty::BorrowKind::UniqueImmutable => {
1436 BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture }
1437 }
1438 ty::BorrowKind::Mutable => {
1439 BorrowKind::Mut { kind: mir::MutBorrowKind::Default }
1440 }
1441 };
1442 Expr {
1443 temp_scope_id,
1444 ty: upvar_ty,
1445 span: closure_expr.span,
1446 kind: ExprKind::Borrow {
1447 borrow_kind,
1448 arg: self.thir.exprs.push(captured_place_expr),
1449 },
1450 }
1451 }
1452 }
1453 }
1454
1455 fn is_upvar(&mut self, var_hir_id: hir::HirId) -> bool {
1456 self.tcx
1457 .upvars_mentioned(self.body_owner)
1458 .is_some_and(|upvars| upvars.contains_key(&var_hir_id))
1459 }
1460
1461 fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> {
1463 fields
1464 .iter()
1465 .map(|field| FieldExpr {
1466 name: self.typeck_results.field_index(field.hir_id),
1467 expr: self.mirror_expr(field.expr),
1468 })
1469 .collect()
1470 }
1471}
1472
1473trait ToBorrowKind {
1474 fn to_borrow_kind(&self) -> BorrowKind;
1475}
1476
1477impl ToBorrowKind for AutoBorrowMutability {
1478 fn to_borrow_kind(&self) -> BorrowKind {
1479 use rustc_middle::ty::adjustment::AllowTwoPhase;
1480 match *self {
1481 AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut {
1482 kind: match allow_two_phase_borrow {
1483 AllowTwoPhase::Yes => mir::MutBorrowKind::TwoPhaseBorrow,
1484 AllowTwoPhase::No => mir::MutBorrowKind::Default,
1485 },
1486 },
1487 AutoBorrowMutability::Not => BorrowKind::Shared,
1488 }
1489 }
1490}
1491
1492impl ToBorrowKind for hir::Mutability {
1493 fn to_borrow_kind(&self) -> BorrowKind {
1494 match *self {
1495 hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
1496 hir::Mutability::Not => BorrowKind::Shared,
1497 }
1498 }
1499}
1500
1501fn bin_op(op: hir::BinOpKind) -> BinOp {
1502 match op {
1503 hir::BinOpKind::Add => BinOp::Add,
1504 hir::BinOpKind::Sub => BinOp::Sub,
1505 hir::BinOpKind::Mul => BinOp::Mul,
1506 hir::BinOpKind::Div => BinOp::Div,
1507 hir::BinOpKind::Rem => BinOp::Rem,
1508 hir::BinOpKind::BitXor => BinOp::BitXor,
1509 hir::BinOpKind::BitAnd => BinOp::BitAnd,
1510 hir::BinOpKind::BitOr => BinOp::BitOr,
1511 hir::BinOpKind::Shl => BinOp::Shl,
1512 hir::BinOpKind::Shr => BinOp::Shr,
1513 hir::BinOpKind::Eq => BinOp::Eq,
1514 hir::BinOpKind::Lt => BinOp::Lt,
1515 hir::BinOpKind::Le => BinOp::Le,
1516 hir::BinOpKind::Ne => BinOp::Ne,
1517 hir::BinOpKind::Ge => BinOp::Ge,
1518 hir::BinOpKind::Gt => BinOp::Gt,
1519 _ => bug!("no equivalent for ast binop {:?}", op),
1520 }
1521}
1522
1523fn assign_op(op: hir::AssignOpKind) -> AssignOp {
1524 match op {
1525 hir::AssignOpKind::AddAssign => AssignOp::AddAssign,
1526 hir::AssignOpKind::SubAssign => AssignOp::SubAssign,
1527 hir::AssignOpKind::MulAssign => AssignOp::MulAssign,
1528 hir::AssignOpKind::DivAssign => AssignOp::DivAssign,
1529 hir::AssignOpKind::RemAssign => AssignOp::RemAssign,
1530 hir::AssignOpKind::BitXorAssign => AssignOp::BitXorAssign,
1531 hir::AssignOpKind::BitAndAssign => AssignOp::BitAndAssign,
1532 hir::AssignOpKind::BitOrAssign => AssignOp::BitOrAssign,
1533 hir::AssignOpKind::ShlAssign => AssignOp::ShlAssign,
1534 hir::AssignOpKind::ShrAssign => AssignOp::ShrAssign,
1535 }
1536}