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