use crate::ty::fold::ValidateBoundVars;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::InferTy::{self, *};
-use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable};
-use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
+use crate::ty::{
+ self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor,
+};
+use crate::ty::{DelaySpanBugEmitted, List, ParamEnv};
use polonius_engine::Atom;
use rustc_data_structures::captures::Captures;
+use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_target::spec::abi;
use std::borrow::Cow;
use std::cmp::Ordering;
+use std::fmt;
use std::marker::PhantomData;
-use std::ops::Range;
+use std::ops::{ControlFlow, Deref, Range};
use ty::util::IntTypeExt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
Str,
/// An array with the given length. Written as `[T; N]`.
- Array(Ty<'tcx>, &'tcx ty::Const<'tcx>),
+ Array(Ty<'tcx>, ty::Const<'tcx>),
/// The pointee of an array slice. Written as `[T]`.
Slice(Ty<'tcx>),
Never,
/// A tuple type. For example, `(i32, bool)`.
- /// Use `TyS::tuple_fields` to iterate over the field types.
- Tuple(SubstsRef<'tcx>),
+ Tuple(&'tcx List<Ty<'tcx>>),
/// The projection of an associated type. For example,
/// `<T as Trait<..>>::N`.
/// in scope on the function that defined the closure,
/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
/// is rather hackily encoded via a scalar type. See
-/// `TyS::to_opt_closure_kind` for details.
+/// `Ty::to_opt_closure_kind` for details.
/// - CS represents the *closure signature*, representing as a `fn()`
/// type. For example, `fn(u32, u32) -> u32` would mean that the closure
/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
}
}
-pub type Region<'tcx> = &'tcx RegionKind;
+/// Use this rather than `TyKind`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>);
+
+impl<'tcx> Deref for Region<'tcx> {
+ type Target = RegionKind;
+
+ fn deref(&self) -> &RegionKind {
+ &self.0.0
+ }
+}
+
+impl<'tcx> fmt::Debug for Region<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.kind())
+ }
+}
/// Representation of regions. Note that the NLL checker uses a distinct
/// representation of regions. For this reason, it internally replaces all the
/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
/// module for more information.
///
+/// Note: operations are on the wrapper `Region` type, which is interned,
+/// rather than this type.
+///
/// ## The Region lattice within a given function
///
/// In general, the region lattice looks like
}
/// Region utilities
-impl RegionKind {
+impl<'tcx> Region<'tcx> {
+ pub fn kind(self) -> RegionKind {
+ *self.0.0
+ }
+
/// Is this region named by the user?
- pub fn has_name(&self) -> bool {
+ pub fn has_name(self) -> bool {
match *self {
- RegionKind::ReEarlyBound(ebr) => ebr.has_name(),
- RegionKind::ReLateBound(_, br) => br.kind.is_named(),
- RegionKind::ReFree(fr) => fr.bound_region.is_named(),
- RegionKind::ReStatic => true,
- RegionKind::ReVar(..) => false,
- RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
- RegionKind::ReEmpty(_) => false,
- RegionKind::ReErased => false,
+ ty::ReEarlyBound(ebr) => ebr.has_name(),
+ ty::ReLateBound(_, br) => br.kind.is_named(),
+ ty::ReFree(fr) => fr.bound_region.is_named(),
+ ty::ReStatic => true,
+ ty::ReVar(..) => false,
+ ty::RePlaceholder(placeholder) => placeholder.name.is_named(),
+ ty::ReEmpty(_) => false,
+ ty::ReErased => false,
}
}
#[inline]
- pub fn is_late_bound(&self) -> bool {
+ pub fn is_static(self) -> bool {
+ matches!(*self, ty::ReStatic)
+ }
+
+ #[inline]
+ pub fn is_erased(self) -> bool {
+ matches!(*self, ty::ReErased)
+ }
+
+ #[inline]
+ pub fn is_late_bound(self) -> bool {
matches!(*self, ty::ReLateBound(..))
}
#[inline]
- pub fn is_placeholder(&self) -> bool {
+ pub fn is_placeholder(self) -> bool {
matches!(*self, ty::RePlaceholder(..))
}
#[inline]
- pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool {
+ pub fn is_empty(self) -> bool {
+ matches!(*self, ty::ReEmpty(..))
+ }
+
+ #[inline]
+ pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
match *self {
ty::ReLateBound(debruijn, _) => debruijn >= index,
_ => false,
}
}
- pub fn type_flags(&self) -> TypeFlags {
+ pub fn type_flags(self) -> TypeFlags {
let mut flags = TypeFlags::empty();
match *self {
/// of the impl, and for all the other highlighted regions, it
/// would return the `DefId` of the function. In other cases (not shown), this
/// function might return the `DefId` of a closure.
- pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId {
- match self {
+ pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
+ match *self {
ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(),
ty::ReFree(fr) => fr.scope,
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
}
/// Type utilities
-impl<'tcx> TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
#[inline(always)]
- pub fn kind(&self) -> &TyKind<'tcx> {
- &self.kind
+ pub fn kind(self) -> &'tcx TyKind<'tcx> {
+ &self.0.0.kind
}
#[inline(always)]
- pub fn flags(&self) -> TypeFlags {
- self.flags
+ pub fn flags(self) -> TypeFlags {
+ self.0.0.flags
}
#[inline]
- pub fn is_unit(&self) -> bool {
+ pub fn is_unit(self) -> bool {
match self.kind() {
Tuple(ref tys) => tys.is_empty(),
_ => false,
}
#[inline]
- pub fn is_never(&self) -> bool {
+ pub fn is_never(self) -> bool {
matches!(self.kind(), Never)
}
#[inline]
- pub fn is_primitive(&self) -> bool {
+ pub fn is_primitive(self) -> bool {
self.kind().is_primitive()
}
#[inline]
- pub fn is_adt(&self) -> bool {
+ pub fn is_adt(self) -> bool {
matches!(self.kind(), Adt(..))
}
#[inline]
- pub fn is_ref(&self) -> bool {
+ pub fn is_ref(self) -> bool {
matches!(self.kind(), Ref(..))
}
#[inline]
- pub fn is_ty_var(&self) -> bool {
+ pub fn is_ty_var(self) -> bool {
matches!(self.kind(), Infer(TyVar(_)))
}
#[inline]
- pub fn ty_vid(&self) -> Option<ty::TyVid> {
+ pub fn ty_vid(self) -> Option<ty::TyVid> {
match self.kind() {
&Infer(TyVar(vid)) => Some(vid),
_ => None,
}
#[inline]
- pub fn is_ty_infer(&self) -> bool {
+ pub fn is_ty_infer(self) -> bool {
matches!(self.kind(), Infer(_))
}
#[inline]
- pub fn is_phantom_data(&self) -> bool {
+ pub fn is_phantom_data(self) -> bool {
if let Adt(def, _) = self.kind() { def.is_phantom_data() } else { false }
}
#[inline]
- pub fn is_bool(&self) -> bool {
+ pub fn is_bool(self) -> bool {
*self.kind() == Bool
}
/// Returns `true` if this type is a `str`.
#[inline]
- pub fn is_str(&self) -> bool {
+ pub fn is_str(self) -> bool {
*self.kind() == Str
}
#[inline]
- pub fn is_param(&self, index: u32) -> bool {
+ pub fn is_param(self, index: u32) -> bool {
match self.kind() {
ty::Param(ref data) => data.index == index,
_ => false,
}
#[inline]
- pub fn is_slice(&self) -> bool {
+ pub fn is_slice(self) -> bool {
match self.kind() {
RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str),
_ => false,
}
#[inline]
- pub fn is_array(&self) -> bool {
+ pub fn is_array(self) -> bool {
matches!(self.kind(), Array(..))
}
#[inline]
- pub fn is_simd(&self) -> bool {
+ pub fn is_simd(self) -> bool {
match self.kind() {
Adt(def, _) => def.repr.simd(),
_ => false,
}
}
- pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind() {
- Array(ty, _) | Slice(ty) => ty,
+ Array(ty, _) | Slice(ty) => *ty,
Str => tcx.types.u8,
_ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
}
}
- pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
+ pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
match self.kind() {
Adt(def, substs) => {
assert!(def.repr.simd(), "`simd_size_and_type` called on non-SIMD type");
// The way we evaluate the `N` in `[T; N]` here only works since we use
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
// if we use it in generic code. See the `simd-array-trait` ui test.
- (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty)
+ (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty)
}
// Otherwise, the fields of this Adt are the SIMD components (and we assume they
// all have the same type).
}
#[inline]
- pub fn is_region_ptr(&self) -> bool {
+ pub fn is_region_ptr(self) -> bool {
matches!(self.kind(), Ref(..))
}
#[inline]
- pub fn is_mutable_ptr(&self) -> bool {
+ pub fn is_mutable_ptr(self) -> bool {
matches!(
self.kind(),
RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
/// Get the mutability of the reference or `None` when not a reference
#[inline]
- pub fn ref_mutability(&self) -> Option<hir::Mutability> {
+ pub fn ref_mutability(self) -> Option<hir::Mutability> {
match self.kind() {
Ref(_, _, mutability) => Some(*mutability),
_ => None,
}
#[inline]
- pub fn is_unsafe_ptr(&self) -> bool {
+ pub fn is_unsafe_ptr(self) -> bool {
matches!(self.kind(), RawPtr(_))
}
/// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
#[inline]
- pub fn is_any_ptr(&self) -> bool {
+ pub fn is_any_ptr(self) -> bool {
self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr()
}
#[inline]
- pub fn is_box(&self) -> bool {
+ pub fn is_box(self) -> bool {
match self.kind() {
Adt(def, _) => def.is_box(),
_ => false,
}
/// Panics if called on any type other than `Box<T>`.
- pub fn boxed_ty(&self) -> Ty<'tcx> {
+ pub fn boxed_ty(self) -> Ty<'tcx> {
match self.kind() {
Adt(def, substs) if def.is_box() => substs.type_at(0),
_ => bug!("`boxed_ty` is called on non-box type {:?}", self),
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
/// contents are abstract to rustc.)
#[inline]
- pub fn is_scalar(&self) -> bool {
+ pub fn is_scalar(self) -> bool {
matches!(
self.kind(),
Bool | Char
/// Returns `true` if this type is a floating point type.
#[inline]
- pub fn is_floating_point(&self) -> bool {
+ pub fn is_floating_point(self) -> bool {
matches!(self.kind(), Float(_) | Infer(FloatVar(_)))
}
#[inline]
- pub fn is_trait(&self) -> bool {
+ pub fn is_trait(self) -> bool {
matches!(self.kind(), Dynamic(..))
}
#[inline]
- pub fn is_enum(&self) -> bool {
+ pub fn is_enum(self) -> bool {
matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
}
#[inline]
- pub fn is_union(&self) -> bool {
+ pub fn is_union(self) -> bool {
matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
}
#[inline]
- pub fn is_closure(&self) -> bool {
+ pub fn is_closure(self) -> bool {
matches!(self.kind(), Closure(..))
}
#[inline]
- pub fn is_generator(&self) -> bool {
+ pub fn is_generator(self) -> bool {
matches!(self.kind(), Generator(..))
}
#[inline]
- pub fn is_integral(&self) -> bool {
+ pub fn is_integral(self) -> bool {
matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
}
#[inline]
- pub fn is_fresh_ty(&self) -> bool {
+ pub fn is_fresh_ty(self) -> bool {
matches!(self.kind(), Infer(FreshTy(_)))
}
#[inline]
- pub fn is_fresh(&self) -> bool {
+ pub fn is_fresh(self) -> bool {
matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_)))
}
#[inline]
- pub fn is_char(&self) -> bool {
+ pub fn is_char(self) -> bool {
matches!(self.kind(), Char)
}
#[inline]
- pub fn is_numeric(&self) -> bool {
+ pub fn is_numeric(self) -> bool {
self.is_integral() || self.is_floating_point()
}
#[inline]
- pub fn is_signed(&self) -> bool {
+ pub fn is_signed(self) -> bool {
matches!(self.kind(), Int(_))
}
#[inline]
- pub fn is_ptr_sized_integral(&self) -> bool {
+ pub fn is_ptr_sized_integral(self) -> bool {
matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
}
#[inline]
- pub fn has_concrete_skeleton(&self) -> bool {
+ pub fn has_concrete_skeleton(self) -> bool {
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
}
+ /// Checks whether a type recursively contains another type
+ ///
+ /// Example: `Option<()>` contains `()`
+ pub fn contains(self, other: Ty<'tcx>) -> bool {
+ struct ContainsTyVisitor<'tcx>(Ty<'tcx>);
+
+ impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> {
+ type BreakTy = ();
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) }
+ }
+ }
+
+ let cf = self.visit_with(&mut ContainsTyVisitor(other));
+ cf.is_break()
+ }
+
/// Returns the type and mutability of `*ty`.
///
/// The parameter `explicit` indicates if this is an *explicit* dereference.
/// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
- pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
+ pub fn builtin_deref(self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
match self.kind() {
Adt(def, _) if def.is_box() => {
Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not })
}
- Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl: *mutbl }),
+ Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
RawPtr(mt) if explicit => Some(*mt),
_ => None,
}
}
/// Returns the type of `ty[i]`.
- pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
+ pub fn builtin_index(self) -> Option<Ty<'tcx>> {
match self.kind() {
- Array(ty, _) | Slice(ty) => Some(ty),
+ Array(ty, _) | Slice(ty) => Some(*ty),
_ => None,
}
}
- pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
+ pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
match self.kind() {
FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs),
FnPtr(f) => *f,
}
#[inline]
- pub fn is_fn(&self) -> bool {
+ pub fn is_fn(self) -> bool {
matches!(self.kind(), FnDef(..) | FnPtr(_))
}
#[inline]
- pub fn is_fn_ptr(&self) -> bool {
+ pub fn is_fn_ptr(self) -> bool {
matches!(self.kind(), FnPtr(_))
}
#[inline]
- pub fn is_impl_trait(&self) -> bool {
+ pub fn is_impl_trait(self) -> bool {
matches!(self.kind(), Opaque(..))
}
#[inline]
- pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> {
+ pub fn ty_adt_def(self) -> Option<&'tcx AdtDef> {
match self.kind() {
Adt(adt, _) => Some(adt),
_ => None,
/// Iterates over tuple fields.
/// Panics when called on anything but a tuple.
- pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> {
+ pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
match self.kind() {
- Tuple(substs) => substs.iter().map(|field| field.expect_ty()),
- _ => bug!("tuple_fields called on non-tuple"),
- }
- }
-
- /// Get the `i`-th element of a tuple.
- /// Panics when called on anything but a tuple.
- pub fn tuple_element_ty(&self, i: usize) -> Option<Ty<'tcx>> {
- match self.kind() {
- Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()),
+ Tuple(substs) => substs,
_ => bug!("tuple_fields called on non-tuple"),
}
}
//
// FIXME: This requires the optimized MIR in the case of generators.
#[inline]
- pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
+ pub fn variant_range(self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
match self.kind() {
TyKind::Adt(adt, _) => Some(adt.variant_range()),
TyKind::Generator(def_id, substs, _) => {
// FIXME: This requires the optimized MIR in the case of generators.
#[inline]
pub fn discriminant_for_variant(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
variant_index: VariantIdx,
) -> Option<Discr<'tcx>> {
}
/// Returns the type of the discriminant of this type.
- pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind() {
ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
/// Returns the type of metadata for (potentially fat) pointers to this type.
pub fn ptr_metadata_ty(
- &'tcx self,
+ self,
tcx: TyCtxt<'tcx>,
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
) -> Ty<'tcx> {
/// to represent the closure kind, because it has not yet been
/// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`)
/// is complete, that type variable will be unified.
- pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
+ pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> {
match self.kind() {
Int(int_ty) => match int_ty {
ty::IntTy::I8 => Some(ty::ClosureKind::Fn),
/// bound such as `[_]: Copy`. A function with such a bound obviously never
/// can be called, but that doesn't mean it shouldn't typecheck. This is why
/// this method doesn't return `Option<bool>`.
- pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
+ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Uint(_)
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false,
- ty::Tuple(tys) => tys.iter().all(|ty| ty.expect_ty().is_trivially_sized(tcx)),
+ ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)),
ty::Adt(def, _substs) => def.sized_constraint(tcx).is_empty(),