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(
92 tcx: TyCtxt<'tcx>,
93 self_ty: Ty<'tcx>,
94 variant_idx: Option<VariantIdx>,
95 f: FieldIdx,
96 ) -> Ty<'tcx> {
97 if let Some(variant_index) = variant_idx {
98 match *self_ty.kind() {
99 ty::Adt(adt_def, args) if adt_def.is_enum() => {
100 adt_def.variant(variant_index).fields[f].ty(tcx, args)
101 }
102 ty::Coroutine(def_id, args) => {
103 let mut variants = args.as_coroutine().state_tys(def_id, tcx);
104 let Some(mut variant) = variants.nth(variant_index.into()) else {
105 bug!("variant {variant_index:?} of coroutine out of range: {self_ty:?}");
106 };
107
108 variant.nth(f.index()).unwrap_or_else(|| {
109 bug!("field {f:?} out of range of variant: {self_ty:?} {variant_idx:?}")
110 })
111 }
112 _ => bug!("can't downcast non-adt non-coroutine type: {self_ty:?}"),
113 }
114 } else {
115 match self_ty.kind() {
116 ty::Adt(adt_def, args) if !adt_def.is_enum() => {
117 adt_def.non_enum_variant().fields[f].ty(tcx, args)
118 }
119 ty::Closure(_, args) => args
120 .as_closure()
121 .upvar_tys()
122 .get(f.index())
123 .copied()
124 .unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")),
125 ty::CoroutineClosure(_, args) => args
126 .as_coroutine_closure()
127 .upvar_tys()
128 .get(f.index())
129 .copied()
130 .unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")),
131 ty::Coroutine(_, args) => {
134 args.as_coroutine().prefix_tys().get(f.index()).copied().unwrap_or_else(|| {
135 bug!("field {f:?} out of range of prefixes for {self_ty}")
136 })
137 }
138 ty::Tuple(tys) => tys
139 .get(f.index())
140 .copied()
141 .unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")),
142 _ => bug!("can't project out of {self_ty:?}"),
143 }
144 }
145 }
146
147 pub fn multi_projection_ty(
148 self,
149 tcx: TyCtxt<'tcx>,
150 elems: &[PlaceElem<'tcx>],
151 ) -> PlaceTy<'tcx> {
152 elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
153 }
154
155 pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
159 self.projection_ty_core(tcx, &elem, |ty| ty, |_, _, _, ty| ty, |ty| ty)
160 }
161
162 pub fn projection_ty_core<V, T>(
168 self,
169 tcx: TyCtxt<'tcx>,
170 elem: &ProjectionElem<V, T>,
171 mut structurally_normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
172 mut handle_field: impl FnMut(Ty<'tcx>, Option<VariantIdx>, FieldIdx, T) -> Ty<'tcx>,
173 mut handle_opaque_cast_and_subtype: impl FnMut(T) -> Ty<'tcx>,
174 ) -> PlaceTy<'tcx>
175 where
176 V: ::std::fmt::Debug,
177 T: ::std::fmt::Debug + Copy,
178 {
179 if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
180 bug!("cannot use non field projection on downcasted place")
181 }
182 let answer = match *elem {
183 ProjectionElem::Deref => {
184 let ty = structurally_normalize(self.ty).builtin_deref(true).unwrap_or_else(|| {
185 bug!("deref projection of non-dereferenceable ty {:?}", self)
186 });
187 PlaceTy::from_ty(ty)
188 }
189 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
190 PlaceTy::from_ty(structurally_normalize(self.ty).builtin_index().unwrap())
191 }
192 ProjectionElem::Subslice { from, to, from_end } => {
193 PlaceTy::from_ty(match structurally_normalize(self.ty).kind() {
194 ty::Slice(..) => self.ty,
195 ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
196 ty::Array(inner, size) if from_end => {
197 let size = size
198 .try_to_target_usize(tcx)
199 .expect("expected subslice projection on fixed-size array");
200 let len = size - from - to;
201 Ty::new_array(tcx, *inner, len)
202 }
203 _ => bug!("cannot subslice non-array type: `{:?}`", self),
204 })
205 }
206 ProjectionElem::Downcast(_name, index) => {
207 PlaceTy { ty: self.ty, variant_index: Some(index) }
208 }
209 ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(
210 structurally_normalize(self.ty),
211 self.variant_index,
212 f,
213 fty,
214 )),
215 ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
216 ProjectionElem::Subtype(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
217
218 ProjectionElem::UnwrapUnsafeBinder(ty) => {
220 PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty))
221 }
222 };
223 debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
224 answer
225 }
226}
227
228impl<V, T> ProjectionElem<V, T> {
229 fn is_indirect(&self) -> bool {
232 match self {
233 Self::Deref => true,
234
235 Self::Field(_, _)
236 | Self::Index(_)
237 | Self::OpaqueCast(_)
238 | Self::Subtype(_)
239 | Self::ConstantIndex { .. }
240 | Self::Subslice { .. }
241 | Self::Downcast(_, _)
242 | Self::UnwrapUnsafeBinder(..) => false,
243 }
244 }
245
246 pub fn is_stable_offset(&self) -> bool {
249 match self {
250 Self::Deref | Self::Index(_) => false,
251 Self::Field(_, _)
252 | Self::OpaqueCast(_)
253 | Self::Subtype(_)
254 | Self::ConstantIndex { .. }
255 | Self::Subslice { .. }
256 | Self::Downcast(_, _)
257 | Self::UnwrapUnsafeBinder(..) => true,
258 }
259 }
260
261 pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
263 matches!(*self, Self::Downcast(_, x) if x == v)
264 }
265
266 pub fn is_field_to(&self, f: FieldIdx) -> bool {
268 matches!(*self, Self::Field(x, _) if x == f)
269 }
270
271 pub fn can_use_in_debuginfo(&self) -> bool {
273 match self {
274 Self::ConstantIndex { from_end: false, .. }
275 | Self::Deref
276 | Self::Downcast(_, _)
277 | Self::Field(_, _) => true,
278 Self::ConstantIndex { from_end: true, .. }
279 | Self::Index(_)
280 | Self::Subtype(_)
281 | Self::OpaqueCast(_)
282 | Self::Subslice { .. } => false,
283
284 Self::UnwrapUnsafeBinder(..) => false,
286 }
287 }
288}
289
290pub type ProjectionKind = ProjectionElem<(), ()>;
293
294#[derive(Clone, Copy, PartialEq, Eq, Hash)]
295pub struct PlaceRef<'tcx> {
296 pub local: Local,
297 pub projection: &'tcx [PlaceElem<'tcx>],
298}
299
300impl<'tcx> !PartialOrd for PlaceRef<'tcx> {}
305
306impl<'tcx> Place<'tcx> {
307 pub fn return_place() -> Place<'tcx> {
309 Place { local: RETURN_PLACE, projection: List::empty() }
310 }
311
312 pub fn is_indirect(&self) -> bool {
317 self.projection.iter().any(|elem| elem.is_indirect())
318 }
319
320 pub fn is_indirect_first_projection(&self) -> bool {
326 self.as_ref().is_indirect_first_projection()
327 }
328
329 #[inline(always)]
332 pub fn local_or_deref_local(&self) -> Option<Local> {
333 self.as_ref().local_or_deref_local()
334 }
335
336 #[inline(always)]
339 pub fn as_local(&self) -> Option<Local> {
340 self.as_ref().as_local()
341 }
342
343 #[inline]
344 pub fn as_ref(&self) -> PlaceRef<'tcx> {
345 PlaceRef { local: self.local, projection: self.projection }
346 }
347
348 #[inline]
356 pub fn iter_projections(
357 self,
358 ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
359 self.as_ref().iter_projections()
360 }
361
362 pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
365 if more_projections.is_empty() {
366 return self;
367 }
368
369 self.as_ref().project_deeper(more_projections, tcx)
370 }
371
372 pub fn ty_from<D: ?Sized>(
373 local: Local,
374 projection: &[PlaceElem<'tcx>],
375 local_decls: &D,
376 tcx: TyCtxt<'tcx>,
377 ) -> PlaceTy<'tcx>
378 where
379 D: HasLocalDecls<'tcx>,
380 {
381 PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection)
382 }
383
384 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
385 where
386 D: HasLocalDecls<'tcx>,
387 {
388 Place::ty_from(self.local, self.projection, local_decls, tcx)
389 }
390}
391
392impl From<Local> for Place<'_> {
393 #[inline]
394 fn from(local: Local) -> Self {
395 Place { local, projection: List::empty() }
396 }
397}
398
399impl<'tcx> PlaceRef<'tcx> {
400 pub fn local_or_deref_local(&self) -> Option<Local> {
403 match *self {
404 PlaceRef { local, projection: [] }
405 | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
406 _ => None,
407 }
408 }
409
410 pub fn is_indirect(&self) -> bool {
415 self.projection.iter().any(|elem| elem.is_indirect())
416 }
417
418 pub fn is_indirect_first_projection(&self) -> bool {
424 debug_assert!(
426 self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
427 );
428 self.projection.first() == Some(&PlaceElem::Deref)
429 }
430
431 #[inline]
434 pub fn as_local(&self) -> Option<Local> {
435 match *self {
436 PlaceRef { local, projection: [] } => Some(local),
437 _ => None,
438 }
439 }
440
441 #[inline]
442 pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
443 Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
444 }
445
446 #[inline]
447 pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
448 if let &[ref proj_base @ .., elem] = self.projection {
449 Some((PlaceRef { local: self.local, projection: proj_base }, elem))
450 } else {
451 None
452 }
453 }
454
455 #[inline]
463 pub fn iter_projections(
464 self,
465 ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
466 self.projection.iter().enumerate().map(move |(i, proj)| {
467 let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
468 (base, *proj)
469 })
470 }
471
472 pub fn project_deeper(
475 self,
476 more_projections: &[PlaceElem<'tcx>],
477 tcx: TyCtxt<'tcx>,
478 ) -> Place<'tcx> {
479 let mut v: Vec<PlaceElem<'tcx>>;
480
481 let new_projections = if self.projection.is_empty() {
482 more_projections
483 } else {
484 v = Vec::with_capacity(self.projection.len() + more_projections.len());
485 v.extend(self.projection);
486 v.extend(more_projections);
487 &v
488 };
489
490 Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
491 }
492
493 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
494 where
495 D: HasLocalDecls<'tcx>,
496 {
497 Place::ty_from(self.local, self.projection, local_decls, tcx)
498 }
499}
500
501impl From<Local> for PlaceRef<'_> {
502 #[inline]
503 fn from(local: Local) -> Self {
504 PlaceRef { local, projection: &[] }
505 }
506}
507
508impl<'tcx> Operand<'tcx> {
512 pub fn function_handle(
516 tcx: TyCtxt<'tcx>,
517 def_id: DefId,
518 args: impl IntoIterator<Item = GenericArg<'tcx>>,
519 span: Span,
520 ) -> Self {
521 let ty = Ty::new_fn_def(tcx, def_id, args);
522 Operand::Constant(Box::new(ConstOperand {
523 span,
524 user_ty: None,
525 const_: Const::Val(ConstValue::ZeroSized, ty),
526 }))
527 }
528
529 pub fn is_move(&self) -> bool {
530 matches!(self, Operand::Move(..))
531 }
532
533 pub fn const_from_scalar(
536 tcx: TyCtxt<'tcx>,
537 ty: Ty<'tcx>,
538 val: Scalar,
539 span: Span,
540 ) -> Operand<'tcx> {
541 debug_assert!({
542 let typing_env = ty::TypingEnv::fully_monomorphized();
543 let type_size = tcx
544 .layout_of(typing_env.as_query_input(ty))
545 .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
546 .size;
547 let scalar_size = match val {
548 Scalar::Int(int) => int.size(),
549 _ => panic!("Invalid scalar type {val:?}"),
550 };
551 scalar_size == type_size
552 });
553 Operand::Constant(Box::new(ConstOperand {
554 span,
555 user_ty: None,
556 const_: Const::Val(ConstValue::Scalar(val), ty),
557 }))
558 }
559
560 pub fn to_copy(&self) -> Self {
561 match *self {
562 Operand::Copy(_) | Operand::Constant(_) => self.clone(),
563 Operand::Move(place) => Operand::Copy(place),
564 }
565 }
566
567 pub fn place(&self) -> Option<Place<'tcx>> {
570 match self {
571 Operand::Copy(place) | Operand::Move(place) => Some(*place),
572 Operand::Constant(_) => None,
573 }
574 }
575
576 pub fn constant(&self) -> Option<&ConstOperand<'tcx>> {
579 match self {
580 Operand::Constant(x) => Some(&**x),
581 Operand::Copy(_) | Operand::Move(_) => None,
582 }
583 }
584
585 pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
590 let const_ty = self.constant()?.const_.ty();
591 if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
592 }
593
594 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
595 where
596 D: HasLocalDecls<'tcx>,
597 {
598 match self {
599 &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
600 Operand::Constant(c) => c.const_.ty(),
601 }
602 }
603
604 pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span
605 where
606 D: HasLocalDecls<'tcx>,
607 {
608 match self {
609 &Operand::Copy(ref l) | &Operand::Move(ref l) => {
610 local_decls.local_decls()[l.local].source_info.span
611 }
612 Operand::Constant(c) => c.span,
613 }
614 }
615}
616
617impl<'tcx> ConstOperand<'tcx> {
618 pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
619 match self.const_.try_to_scalar() {
620 Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance.alloc_id()) {
621 GlobalAlloc::Static(def_id) => {
622 assert!(!tcx.is_thread_local_static(def_id));
623 Some(def_id)
624 }
625 _ => None,
626 },
627 _ => None,
628 }
629 }
630
631 #[inline]
632 pub fn ty(&self) -> Ty<'tcx> {
633 self.const_.ty()
634 }
635}
636
637pub enum RvalueInitializationState {
641 Shallow,
642 Deep,
643}
644
645impl<'tcx> Rvalue<'tcx> {
646 #[inline]
648 pub fn is_safe_to_remove(&self) -> bool {
649 match self {
650 Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => false,
654
655 Rvalue::Use(_)
656 | Rvalue::CopyForDeref(_)
657 | Rvalue::Repeat(_, _)
658 | Rvalue::Ref(_, _, _)
659 | Rvalue::ThreadLocalRef(_)
660 | Rvalue::RawPtr(_, _)
661 | Rvalue::Len(_)
662 | Rvalue::Cast(
663 CastKind::IntToInt
664 | CastKind::FloatToInt
665 | CastKind::FloatToFloat
666 | CastKind::IntToFloat
667 | CastKind::FnPtrToPtr
668 | CastKind::PtrToPtr
669 | CastKind::PointerCoercion(_, _)
670 | CastKind::PointerWithExposedProvenance
671 | CastKind::Transmute,
672 _,
673 _,
674 )
675 | Rvalue::BinaryOp(_, _)
676 | Rvalue::NullaryOp(_, _)
677 | Rvalue::UnaryOp(_, _)
678 | Rvalue::Discriminant(_)
679 | Rvalue::Aggregate(_, _)
680 | Rvalue::ShallowInitBox(_, _)
681 | Rvalue::WrapUnsafeBinder(_, _) => true,
682 }
683 }
684
685 pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
686 where
687 D: HasLocalDecls<'tcx>,
688 {
689 match *self {
690 Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
691 Rvalue::Repeat(ref operand, count) => {
692 Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count)
693 }
694 Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
695 Rvalue::Ref(reg, bk, ref place) => {
696 let place_ty = place.ty(local_decls, tcx).ty;
697 Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
698 }
699 Rvalue::RawPtr(kind, ref place) => {
700 let place_ty = place.ty(local_decls, tcx).ty;
701 Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
702 }
703 Rvalue::Len(..) => tcx.types.usize,
704 Rvalue::Cast(.., ty) => ty,
705 Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
706 let lhs_ty = lhs.ty(local_decls, tcx);
707 let rhs_ty = rhs.ty(local_decls, tcx);
708 op.ty(tcx, lhs_ty, rhs_ty)
709 }
710 Rvalue::UnaryOp(op, ref operand) => {
711 let arg_ty = operand.ty(local_decls, tcx);
712 op.ty(tcx, arg_ty)
713 }
714 Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
715 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
716 tcx.types.usize
717 }
718 Rvalue::NullaryOp(NullOp::ContractChecks, _)
719 | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
720 Rvalue::Aggregate(ref ak, ref ops) => match **ak {
721 AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
722 AggregateKind::Tuple => {
723 Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx)))
724 }
725 AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args),
726 AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args),
727 AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args),
728 AggregateKind::CoroutineClosure(did, args) => {
729 Ty::new_coroutine_closure(tcx, did, args)
730 }
731 AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability),
732 },
733 Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
734 Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
735 Rvalue::WrapUnsafeBinder(_, ty) => ty,
736 }
737 }
738
739 #[inline]
740 pub fn initialization_state(&self) -> RvalueInitializationState {
743 match *self {
744 Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
745 _ => RvalueInitializationState::Deep,
746 }
747 }
748}
749
750impl BorrowKind {
751 pub fn mutability(&self) -> Mutability {
752 match *self {
753 BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not,
754 BorrowKind::Mut { .. } => Mutability::Mut,
755 }
756 }
757
758 pub fn allows_two_phase_borrow(&self) -> bool {
761 match *self {
762 BorrowKind::Shared
763 | BorrowKind::Fake(_)
764 | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
765 false
766 }
767 BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true,
768 }
769 }
770
771 pub fn to_mutbl_lossy(self) -> hir::Mutability {
772 match self {
773 BorrowKind::Mut { .. } => hir::Mutability::Mut,
774 BorrowKind::Shared => hir::Mutability::Not,
775
776 BorrowKind::Fake(_) => hir::Mutability::Not,
779 }
780 }
781}
782
783impl<'tcx> NullOp<'tcx> {
784 pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
785 match self {
786 NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) => tcx.types.usize,
787 NullOp::UbChecks | NullOp::ContractChecks => tcx.types.bool,
788 }
789 }
790}
791
792impl<'tcx> UnOp {
793 pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
794 match self {
795 UnOp::Not | UnOp::Neg => arg_ty,
796 UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx),
797 }
798 }
799}
800
801impl<'tcx> BinOp {
802 pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
803 match self {
805 &BinOp::Add
806 | &BinOp::AddUnchecked
807 | &BinOp::Sub
808 | &BinOp::SubUnchecked
809 | &BinOp::Mul
810 | &BinOp::MulUnchecked
811 | &BinOp::Div
812 | &BinOp::Rem
813 | &BinOp::BitXor
814 | &BinOp::BitAnd
815 | &BinOp::BitOr => {
816 assert_eq!(lhs_ty, rhs_ty);
818 lhs_ty
819 }
820 &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => {
821 assert_eq!(lhs_ty, rhs_ty);
823 Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool])
824 }
825 &BinOp::Shl
826 | &BinOp::ShlUnchecked
827 | &BinOp::Shr
828 | &BinOp::ShrUnchecked
829 | &BinOp::Offset => {
830 lhs_ty }
832 &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
833 tcx.types.bool
834 }
835 &BinOp::Cmp => {
836 assert_eq!(lhs_ty, rhs_ty);
838 tcx.ty_ordering_enum(None)
839 }
840 }
841 }
842 pub(crate) fn to_hir_binop(self) -> hir::BinOpKind {
843 match self {
844 BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add,
847 BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub,
848 BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul,
849 BinOp::Div => hir::BinOpKind::Div,
850 BinOp::Rem => hir::BinOpKind::Rem,
851 BinOp::BitXor => hir::BinOpKind::BitXor,
852 BinOp::BitAnd => hir::BinOpKind::BitAnd,
853 BinOp::BitOr => hir::BinOpKind::BitOr,
854 BinOp::Shl => hir::BinOpKind::Shl,
855 BinOp::Shr => hir::BinOpKind::Shr,
856 BinOp::Eq => hir::BinOpKind::Eq,
857 BinOp::Ne => hir::BinOpKind::Ne,
858 BinOp::Lt => hir::BinOpKind::Lt,
859 BinOp::Gt => hir::BinOpKind::Gt,
860 BinOp::Le => hir::BinOpKind::Le,
861 BinOp::Ge => hir::BinOpKind::Ge,
862 BinOp::Cmp
864 | BinOp::AddUnchecked
865 | BinOp::SubUnchecked
866 | BinOp::MulUnchecked
867 | BinOp::ShlUnchecked
868 | BinOp::ShrUnchecked
869 | BinOp::Offset => {
870 unreachable!()
871 }
872 }
873 }
874
875 pub fn overflowing_to_wrapping(self) -> Option<BinOp> {
877 Some(match self {
878 BinOp::AddWithOverflow => BinOp::Add,
879 BinOp::SubWithOverflow => BinOp::Sub,
880 BinOp::MulWithOverflow => BinOp::Mul,
881 _ => return None,
882 })
883 }
884
885 pub fn is_overflowing(self) -> bool {
887 self.overflowing_to_wrapping().is_some()
888 }
889
890 pub fn wrapping_to_overflowing(self) -> Option<BinOp> {
892 Some(match self {
893 BinOp::Add => BinOp::AddWithOverflow,
894 BinOp::Sub => BinOp::SubWithOverflow,
895 BinOp::Mul => BinOp::MulWithOverflow,
896 _ => return None,
897 })
898 }
899}
900
901impl From<Mutability> for RawPtrKind {
902 fn from(other: Mutability) -> Self {
903 match other {
904 Mutability::Mut => RawPtrKind::Mut,
905 Mutability::Not => RawPtrKind::Const,
906 }
907 }
908}
909
910impl RawPtrKind {
911 pub fn is_fake(self) -> bool {
912 match self {
913 RawPtrKind::Mut | RawPtrKind::Const => false,
914 RawPtrKind::FakeForPtrMetadata => true,
915 }
916 }
917
918 pub fn to_mutbl_lossy(self) -> Mutability {
919 match self {
920 RawPtrKind::Mut => Mutability::Mut,
921 RawPtrKind::Const => Mutability::Not,
922
923 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
926 }
927 }
928
929 pub fn ptr_str(self) -> &'static str {
930 match self {
931 RawPtrKind::Mut => "mut",
932 RawPtrKind::Const => "const",
933 RawPtrKind::FakeForPtrMetadata => "const (fake)",
934 }
935 }
936}