1use tracing::{debug, instrument};
4
5use super::interpret::GlobalAlloc;
6use super::*;
7use crate::ty::CoroutineArgsExt;
8
9#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
14pub struct Statement<'tcx> {
15 pub source_info: SourceInfo,
16 pub kind: StatementKind<'tcx>,
17}
18
19impl Statement<'_> {
20 pub fn make_nop(&mut self) {
23 self.kind = StatementKind::Nop
24 }
25}
26
27impl<'tcx> StatementKind<'tcx> {
28 pub const fn name(&self) -> &'static str {
31 match self {
32 StatementKind::Assign(..) => "Assign",
33 StatementKind::FakeRead(..) => "FakeRead",
34 StatementKind::SetDiscriminant { .. } => "SetDiscriminant",
35 StatementKind::Deinit(..) => "Deinit",
36 StatementKind::StorageLive(..) => "StorageLive",
37 StatementKind::StorageDead(..) => "StorageDead",
38 StatementKind::Retag(..) => "Retag",
39 StatementKind::PlaceMention(..) => "PlaceMention",
40 StatementKind::AscribeUserType(..) => "AscribeUserType",
41 StatementKind::Coverage(..) => "Coverage",
42 StatementKind::Intrinsic(..) => "Intrinsic",
43 StatementKind::ConstEvalCounter => "ConstEvalCounter",
44 StatementKind::Nop => "Nop",
45 StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint",
46 }
47 }
48 pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> {
49 match self {
50 StatementKind::Assign(x) => Some(x),
51 _ => None,
52 }
53 }
54
55 pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> {
56 match self {
57 StatementKind::Assign(x) => Some(x),
58 _ => None,
59 }
60 }
61}
62
63#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
67pub struct PlaceTy<'tcx> {
68 pub ty: Ty<'tcx>,
69 pub variant_index: Option<VariantIdx>,
71}
72
73#[cfg(target_pointer_width = "64")]
75rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16);
76
77impl<'tcx> PlaceTy<'tcx> {
78 #[inline]
79 pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
80 PlaceTy { ty, variant_index: None }
81 }
82
83 #[instrument(level = "debug", skip(tcx), ret)]
91 pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> {
92 if let Some(variant_index) = self.variant_index {
93 match *self.ty.kind() {
94 ty::Adt(adt_def, args) if adt_def.is_enum() => {
95 adt_def.variant(variant_index).fields[f].ty(tcx, args)
96 }
97 ty::Coroutine(def_id, args) => {
98 let mut variants = args.as_coroutine().state_tys(def_id, tcx);
99 let Some(mut variant) = variants.nth(variant_index.into()) else {
100 bug!("variant {variant_index:?} of coroutine out of range: {self:?}");
101 };
102
103 variant
104 .nth(f.index())
105 .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}"))
106 }
107 _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"),
108 }
109 } else {
110 match self.ty.kind() {
111 ty::Adt(adt_def, args) if !adt_def.is_enum() => {
112 adt_def.non_enum_variant().fields[f].ty(tcx, args)
113 }
114 ty::Closure(_, args) => args
115 .as_closure()
116 .upvar_tys()
117 .get(f.index())
118 .copied()
119 .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
120 ty::CoroutineClosure(_, args) => args
121 .as_coroutine_closure()
122 .upvar_tys()
123 .get(f.index())
124 .copied()
125 .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
126 ty::Coroutine(_, args) => args
129 .as_coroutine()
130 .prefix_tys()
131 .get(f.index())
132 .copied()
133 .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
134 ty::Tuple(tys) => tys
135 .get(f.index())
136 .copied()
137 .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
138 _ => bug!("can't project out of {self:?}"),
139 }
140 }
141 }
142
143 pub fn multi_projection_ty(
144 self,
145 tcx: TyCtxt<'tcx>,
146 elems: &[PlaceElem<'tcx>],
147 ) -> PlaceTy<'tcx> {
148 elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
149 }
150
151 pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
155 self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty)
156 }
157
158 pub fn projection_ty_core<V, T>(
164 self,
165 tcx: TyCtxt<'tcx>,
166 elem: &ProjectionElem<V, T>,
167 mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
168 mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
169 ) -> PlaceTy<'tcx>
170 where
171 V: ::std::fmt::Debug,
172 T: ::std::fmt::Debug + Copy,
173 {
174 if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
175 bug!("cannot use non field projection on downcasted place")
176 }
177 let answer = match *elem {
178 ProjectionElem::Deref => {
179 let ty = self.ty.builtin_deref(true).unwrap_or_else(|| {
180 bug!("deref projection of non-dereferenceable ty {:?}", self)
181 });
182 PlaceTy::from_ty(ty)
183 }
184 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
185 PlaceTy::from_ty(self.ty.builtin_index().unwrap())
186 }
187 ProjectionElem::Subslice { from, to, from_end } => {
188 PlaceTy::from_ty(match self.ty.kind() {
189 ty::Slice(..) => self.ty,
190 ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
191 ty::Array(inner, size) if from_end => {
192 let size = size
193 .try_to_target_usize(tcx)
194 .expect("expected subslice projection on fixed-size array");
195 let len = size - from - to;
196 Ty::new_array(tcx, *inner, len)
197 }
198 _ => bug!("cannot subslice non-array type: `{:?}`", self),
199 })
200 }
201 ProjectionElem::Downcast(_name, index) => {
202 PlaceTy { ty: self.ty, variant_index: Some(index) }
203 }
204 ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
205 ProjectionElem::OpaqueCast(ty) => {
206 PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
207 }
208 ProjectionElem::Subtype(ty) => {
209 PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
210 }
211
212 ProjectionElem::UnwrapUnsafeBinder(ty) => {
214 PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
215 }
216 };
217 debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
218 answer
219 }
220}
221
222impl<V, T> ProjectionElem<V, T> {
223 fn is_indirect(&self) -> bool {
226 match self {
227 Self::Deref => true,
228
229 Self::Field(_, _)
230 | Self::Index(_)
231 | Self::OpaqueCast(_)
232 | Self::Subtype(_)
233 | Self::ConstantIndex { .. }
234 | Self::Subslice { .. }
235 | Self::Downcast(_, _)
236 | Self::UnwrapUnsafeBinder(..) => false,
237 }
238 }
239
240 pub fn is_stable_offset(&self) -> bool {
243 match self {
244 Self::Deref | Self::Index(_) => false,
245 Self::Field(_, _)
246 | Self::OpaqueCast(_)
247 | Self::Subtype(_)
248 | Self::ConstantIndex { .. }
249 | Self::Subslice { .. }
250 | Self::Downcast(_, _)
251 | Self::UnwrapUnsafeBinder(..) => true,
252 }
253 }
254
255 pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
257 matches!(*self, Self::Downcast(_, x) if x == v)
258 }
259
260 pub fn is_field_to(&self, f: FieldIdx) -> bool {
262 matches!(*self, Self::Field(x, _) if x == f)
263 }
264
265 pub fn can_use_in_debuginfo(&self) -> bool {
267 match self {
268 Self::ConstantIndex { from_end: false, .. }
269 | Self::Deref
270 | Self::Downcast(_, _)
271 | Self::Field(_, _) => true,
272 Self::ConstantIndex { from_end: true, .. }
273 | Self::Index(_)
274 | Self::Subtype(_)
275 | Self::OpaqueCast(_)
276 | Self::Subslice { .. } => false,
277
278 Self::UnwrapUnsafeBinder(..) => false,
280 }
281 }
282}
283
284pub type ProjectionKind = ProjectionElem<(), ()>;
287
288#[derive(Clone, Copy, PartialEq, Eq, Hash)]
289pub struct PlaceRef<'tcx> {
290 pub local: Local,
291 pub projection: &'tcx [PlaceElem<'tcx>],
292}
293
294impl<'tcx> !PartialOrd for PlaceRef<'tcx> {}
299
300impl<'tcx> Place<'tcx> {
301 pub fn return_place() -> Place<'tcx> {
303 Place { local: RETURN_PLACE, projection: List::empty() }
304 }
305
306 pub fn is_indirect(&self) -> bool {
311 self.projection.iter().any(|elem| elem.is_indirect())
312 }
313
314 pub fn is_indirect_first_projection(&self) -> bool {
320 self.as_ref().is_indirect_first_projection()
321 }
322
323 #[inline(always)]
326 pub fn local_or_deref_local(&self) -> Option<Local> {
327 self.as_ref().local_or_deref_local()
328 }
329
330 #[inline(always)]
333 pub fn as_local(&self) -> Option<Local> {
334 self.as_ref().as_local()
335 }
336
337 #[inline]
338 pub fn as_ref(&self) -> PlaceRef<'tcx> {
339 PlaceRef { local: self.local, projection: self.projection }
340 }
341
342 #[inline]
350 pub fn iter_projections(
351 self,
352 ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
353 self.as_ref().iter_projections()
354 }
355
356 pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
359 if more_projections.is_empty() {
360 return self;
361 }
362
363 self.as_ref().project_deeper(more_projections, tcx)
364 }
365
366 pub fn ty_from<D: ?Sized>(
367 local: Local,
368 projection: &[PlaceElem<'tcx>],
369 local_decls: &D,
370 tcx: TyCtxt<'tcx>,
371 ) -> PlaceTy<'tcx>
372 where
373 D: HasLocalDecls<'tcx>,
374 {
375 PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection)
376 }
377
378 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
379 where
380 D: HasLocalDecls<'tcx>,
381 {
382 Place::ty_from(self.local, self.projection, local_decls, tcx)
383 }
384}
385
386impl From<Local> for Place<'_> {
387 #[inline]
388 fn from(local: Local) -> Self {
389 Place { local, projection: List::empty() }
390 }
391}
392
393impl<'tcx> PlaceRef<'tcx> {
394 pub fn local_or_deref_local(&self) -> Option<Local> {
397 match *self {
398 PlaceRef { local, projection: [] }
399 | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
400 _ => None,
401 }
402 }
403
404 pub fn is_indirect(&self) -> bool {
409 self.projection.iter().any(|elem| elem.is_indirect())
410 }
411
412 pub fn is_indirect_first_projection(&self) -> bool {
418 debug_assert!(
420 self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
421 );
422 self.projection.first() == Some(&PlaceElem::Deref)
423 }
424
425 #[inline]
428 pub fn as_local(&self) -> Option<Local> {
429 match *self {
430 PlaceRef { local, projection: [] } => Some(local),
431 _ => None,
432 }
433 }
434
435 #[inline]
436 pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
437 Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
438 }
439
440 #[inline]
441 pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
442 if let &[ref proj_base @ .., elem] = self.projection {
443 Some((PlaceRef { local: self.local, projection: proj_base }, elem))
444 } else {
445 None
446 }
447 }
448
449 #[inline]
457 pub fn iter_projections(
458 self,
459 ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
460 self.projection.iter().enumerate().map(move |(i, proj)| {
461 let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
462 (base, *proj)
463 })
464 }
465
466 pub fn project_deeper(
469 self,
470 more_projections: &[PlaceElem<'tcx>],
471 tcx: TyCtxt<'tcx>,
472 ) -> Place<'tcx> {
473 let mut v: Vec<PlaceElem<'tcx>>;
474
475 let new_projections = if self.projection.is_empty() {
476 more_projections
477 } else {
478 v = Vec::with_capacity(self.projection.len() + more_projections.len());
479 v.extend(self.projection);
480 v.extend(more_projections);
481 &v
482 };
483
484 Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
485 }
486
487 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
488 where
489 D: HasLocalDecls<'tcx>,
490 {
491 Place::ty_from(self.local, self.projection, local_decls, tcx)
492 }
493}
494
495impl From<Local> for PlaceRef<'_> {
496 #[inline]
497 fn from(local: Local) -> Self {
498 PlaceRef { local, projection: &[] }
499 }
500}
501
502impl<'tcx> Operand<'tcx> {
506 pub fn function_handle(
510 tcx: TyCtxt<'tcx>,
511 def_id: DefId,
512 args: impl IntoIterator<Item = GenericArg<'tcx>>,
513 span: Span,
514 ) -> Self {
515 let ty = Ty::new_fn_def(tcx, def_id, args);
516 Operand::Constant(Box::new(ConstOperand {
517 span,
518 user_ty: None,
519 const_: Const::Val(ConstValue::ZeroSized, ty),
520 }))
521 }
522
523 pub fn is_move(&self) -> bool {
524 matches!(self, Operand::Move(..))
525 }
526
527 pub fn const_from_scalar(
530 tcx: TyCtxt<'tcx>,
531 ty: Ty<'tcx>,
532 val: Scalar,
533 span: Span,
534 ) -> Operand<'tcx> {
535 debug_assert!({
536 let typing_env = ty::TypingEnv::fully_monomorphized();
537 let type_size = tcx
538 .layout_of(typing_env.as_query_input(ty))
539 .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
540 .size;
541 let scalar_size = match val {
542 Scalar::Int(int) => int.size(),
543 _ => panic!("Invalid scalar type {val:?}"),
544 };
545 scalar_size == type_size
546 });
547 Operand::Constant(Box::new(ConstOperand {
548 span,
549 user_ty: None,
550 const_: Const::Val(ConstValue::Scalar(val), ty),
551 }))
552 }
553
554 pub fn to_copy(&self) -> Self {
555 match *self {
556 Operand::Copy(_) | Operand::Constant(_) => self.clone(),
557 Operand::Move(place) => Operand::Copy(place),
558 }
559 }
560
561 pub fn place(&self) -> Option<Place<'tcx>> {
564 match self {
565 Operand::Copy(place) | Operand::Move(place) => Some(*place),
566 Operand::Constant(_) => None,
567 }
568 }
569
570 pub fn constant(&self) -> Option<&ConstOperand<'tcx>> {
573 match self {
574 Operand::Constant(x) => Some(&**x),
575 Operand::Copy(_) | Operand::Move(_) => None,
576 }
577 }
578
579 pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
584 let const_ty = self.constant()?.const_.ty();
585 if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
586 }
587
588 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
589 where
590 D: HasLocalDecls<'tcx>,
591 {
592 match self {
593 &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
594 Operand::Constant(c) => c.const_.ty(),
595 }
596 }
597
598 pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span
599 where
600 D: HasLocalDecls<'tcx>,
601 {
602 match self {
603 &Operand::Copy(ref l) | &Operand::Move(ref l) => {
604 local_decls.local_decls()[l.local].source_info.span
605 }
606 Operand::Constant(c) => c.span,
607 }
608 }
609}
610
611impl<'tcx> ConstOperand<'tcx> {
612 pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
613 match self.const_.try_to_scalar() {
614 Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance.alloc_id()) {
615 GlobalAlloc::Static(def_id) => {
616 assert!(!tcx.is_thread_local_static(def_id));
617 Some(def_id)
618 }
619 _ => None,
620 },
621 _ => None,
622 }
623 }
624
625 #[inline]
626 pub fn ty(&self) -> Ty<'tcx> {
627 self.const_.ty()
628 }
629}
630
631pub enum RvalueInitializationState {
635 Shallow,
636 Deep,
637}
638
639impl<'tcx> Rvalue<'tcx> {
640 #[inline]
642 pub fn is_safe_to_remove(&self) -> bool {
643 match self {
644 Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => false,
648
649 Rvalue::Use(_)
650 | Rvalue::CopyForDeref(_)
651 | Rvalue::Repeat(_, _)
652 | Rvalue::Ref(_, _, _)
653 | Rvalue::ThreadLocalRef(_)
654 | Rvalue::RawPtr(_, _)
655 | Rvalue::Len(_)
656 | Rvalue::Cast(
657 CastKind::IntToInt
658 | CastKind::FloatToInt
659 | CastKind::FloatToFloat
660 | CastKind::IntToFloat
661 | CastKind::FnPtrToPtr
662 | CastKind::PtrToPtr
663 | CastKind::PointerCoercion(_, _)
664 | CastKind::PointerWithExposedProvenance
665 | CastKind::Transmute,
666 _,
667 _,
668 )
669 | Rvalue::BinaryOp(_, _)
670 | Rvalue::NullaryOp(_, _)
671 | Rvalue::UnaryOp(_, _)
672 | Rvalue::Discriminant(_)
673 | Rvalue::Aggregate(_, _)
674 | Rvalue::ShallowInitBox(_, _)
675 | Rvalue::WrapUnsafeBinder(_, _) => true,
676 }
677 }
678
679 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
680 where
681 D: HasLocalDecls<'tcx>,
682 {
683 match *self {
684 Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
685 Rvalue::Repeat(ref operand, count) => {
686 Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count)
687 }
688 Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
689 Rvalue::Ref(reg, bk, ref place) => {
690 let place_ty = place.ty(local_decls, tcx).ty;
691 Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
692 }
693 Rvalue::RawPtr(kind, ref place) => {
694 let place_ty = place.ty(local_decls, tcx).ty;
695 Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
696 }
697 Rvalue::Len(..) => tcx.types.usize,
698 Rvalue::Cast(.., ty) => ty,
699 Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
700 let lhs_ty = lhs.ty(local_decls, tcx);
701 let rhs_ty = rhs.ty(local_decls, tcx);
702 op.ty(tcx, lhs_ty, rhs_ty)
703 }
704 Rvalue::UnaryOp(op, ref operand) => {
705 let arg_ty = operand.ty(local_decls, tcx);
706 op.ty(tcx, arg_ty)
707 }
708 Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
709 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
710 tcx.types.usize
711 }
712 Rvalue::NullaryOp(NullOp::ContractChecks, _)
713 | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
714 Rvalue::Aggregate(ref ak, ref ops) => match **ak {
715 AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
716 AggregateKind::Tuple => {
717 Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx)))
718 }
719 AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args),
720 AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args),
721 AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args),
722 AggregateKind::CoroutineClosure(did, args) => {
723 Ty::new_coroutine_closure(tcx, did, args)
724 }
725 AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability),
726 },
727 Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
728 Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
729 Rvalue::WrapUnsafeBinder(_, ty) => ty,
730 }
731 }
732
733 #[inline]
734 pub fn initialization_state(&self) -> RvalueInitializationState {
737 match *self {
738 Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
739 _ => RvalueInitializationState::Deep,
740 }
741 }
742}
743
744impl BorrowKind {
745 pub fn mutability(&self) -> Mutability {
746 match *self {
747 BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not,
748 BorrowKind::Mut { .. } => Mutability::Mut,
749 }
750 }
751
752 pub fn allows_two_phase_borrow(&self) -> bool {
755 match *self {
756 BorrowKind::Shared
757 | BorrowKind::Fake(_)
758 | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
759 false
760 }
761 BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true,
762 }
763 }
764
765 pub fn to_mutbl_lossy(self) -> hir::Mutability {
766 match self {
767 BorrowKind::Mut { .. } => hir::Mutability::Mut,
768 BorrowKind::Shared => hir::Mutability::Not,
769
770 BorrowKind::Fake(_) => hir::Mutability::Not,
773 }
774 }
775}
776
777impl<'tcx> NullOp<'tcx> {
778 pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
779 match self {
780 NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) => tcx.types.usize,
781 NullOp::UbChecks | NullOp::ContractChecks => tcx.types.bool,
782 }
783 }
784}
785
786impl<'tcx> UnOp {
787 pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
788 match self {
789 UnOp::Not | UnOp::Neg => arg_ty,
790 UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx),
791 }
792 }
793}
794
795impl<'tcx> BinOp {
796 pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
797 match self {
799 &BinOp::Add
800 | &BinOp::AddUnchecked
801 | &BinOp::Sub
802 | &BinOp::SubUnchecked
803 | &BinOp::Mul
804 | &BinOp::MulUnchecked
805 | &BinOp::Div
806 | &BinOp::Rem
807 | &BinOp::BitXor
808 | &BinOp::BitAnd
809 | &BinOp::BitOr => {
810 assert_eq!(lhs_ty, rhs_ty);
812 lhs_ty
813 }
814 &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => {
815 assert_eq!(lhs_ty, rhs_ty);
817 Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool])
818 }
819 &BinOp::Shl
820 | &BinOp::ShlUnchecked
821 | &BinOp::Shr
822 | &BinOp::ShrUnchecked
823 | &BinOp::Offset => {
824 lhs_ty }
826 &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
827 tcx.types.bool
828 }
829 &BinOp::Cmp => {
830 assert_eq!(lhs_ty, rhs_ty);
832 tcx.ty_ordering_enum(None)
833 }
834 }
835 }
836 pub(crate) fn to_hir_binop(self) -> hir::BinOpKind {
837 match self {
838 BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add,
841 BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub,
842 BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul,
843 BinOp::Div => hir::BinOpKind::Div,
844 BinOp::Rem => hir::BinOpKind::Rem,
845 BinOp::BitXor => hir::BinOpKind::BitXor,
846 BinOp::BitAnd => hir::BinOpKind::BitAnd,
847 BinOp::BitOr => hir::BinOpKind::BitOr,
848 BinOp::Shl => hir::BinOpKind::Shl,
849 BinOp::Shr => hir::BinOpKind::Shr,
850 BinOp::Eq => hir::BinOpKind::Eq,
851 BinOp::Ne => hir::BinOpKind::Ne,
852 BinOp::Lt => hir::BinOpKind::Lt,
853 BinOp::Gt => hir::BinOpKind::Gt,
854 BinOp::Le => hir::BinOpKind::Le,
855 BinOp::Ge => hir::BinOpKind::Ge,
856 BinOp::Cmp
858 | BinOp::AddUnchecked
859 | BinOp::SubUnchecked
860 | BinOp::MulUnchecked
861 | BinOp::ShlUnchecked
862 | BinOp::ShrUnchecked
863 | BinOp::Offset => {
864 unreachable!()
865 }
866 }
867 }
868
869 pub fn overflowing_to_wrapping(self) -> Option<BinOp> {
871 Some(match self {
872 BinOp::AddWithOverflow => BinOp::Add,
873 BinOp::SubWithOverflow => BinOp::Sub,
874 BinOp::MulWithOverflow => BinOp::Mul,
875 _ => return None,
876 })
877 }
878
879 pub fn is_overflowing(self) -> bool {
881 self.overflowing_to_wrapping().is_some()
882 }
883
884 pub fn wrapping_to_overflowing(self) -> Option<BinOp> {
886 Some(match self {
887 BinOp::Add => BinOp::AddWithOverflow,
888 BinOp::Sub => BinOp::SubWithOverflow,
889 BinOp::Mul => BinOp::MulWithOverflow,
890 _ => return None,
891 })
892 }
893}
894
895impl From<Mutability> for RawPtrKind {
896 fn from(other: Mutability) -> Self {
897 match other {
898 Mutability::Mut => RawPtrKind::Mut,
899 Mutability::Not => RawPtrKind::Const,
900 }
901 }
902}
903
904impl RawPtrKind {
905 pub fn is_fake(self) -> bool {
906 match self {
907 RawPtrKind::Mut | RawPtrKind::Const => false,
908 RawPtrKind::FakeForPtrMetadata => true,
909 }
910 }
911
912 pub fn to_mutbl_lossy(self) -> Mutability {
913 match self {
914 RawPtrKind::Mut => Mutability::Mut,
915 RawPtrKind::Const => Mutability::Not,
916
917 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
920 }
921 }
922
923 pub fn ptr_str(self) -> &'static str {
924 match self {
925 RawPtrKind::Mut => "mut",
926 RawPtrKind::Const => "const",
927 RawPtrKind::FakeForPtrMetadata => "const (fake)",
928 }
929 }
930}