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