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