]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_middle/src/ty/sty.rs
Rollup merge of #94178 - est31:tolerant_lines_check, r=Mark-Simulacrum
[rust.git] / compiler / rustc_middle / src / ty / sty.rs
index 7d4af6cfa405257088c8e41bb3c1ed5cc89151b7..02a4df637d88946b25ac850550ca5d0bafeb44c4 100644 (file)
@@ -8,10 +8,13 @@
 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;
@@ -21,8 +24,9 @@
 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)]
@@ -74,10 +78,10 @@ pub fn is_named(&self) -> bool {
     }
 }
 
-/// Defines the kinds of types.
+/// Defines the kinds of types used by the type system.
 ///
-/// N.B., if you change this, you'll probably want to change the corresponding
-/// AST structure in `rustc_ast/src/ast.rs` as well.
+/// Types written by the user start out as [hir::TyKind](rustc_hir::TyKind) and get
+/// converted to this representation using `AstConv::ast_ty_to_ty`.
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)]
 #[derive(HashStable)]
 #[rustc_diagnostic_item = "TyKind"]
@@ -100,10 +104,11 @@ pub enum TyKind<'tcx> {
 
     /// Algebraic data types (ADT). For example: structures, enumerations and unions.
     ///
-    /// InternalSubsts here, possibly against intuition, *may* contain `Param`s.
-    /// That is, even after substitution it is possible that there are type
-    /// variables. This happens when the `Adt` corresponds to an ADT
-    /// definition and not a concrete use of it.
+    /// For example, the type `List<i32>` would be represented using the `AdtDef`
+    /// for `struct List<T>` and the substs `[i32]`.
+    ///
+    /// Note that generic parameters in fields only get lazily substituted
+    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
     Adt(&'tcx AdtDef, SubstsRef<'tcx>),
 
     /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
@@ -112,8 +117,8 @@ pub enum TyKind<'tcx> {
     /// The pointee of a string slice. Written as `str`.
     Str,
 
-    /// An array with the given length. Written as `[T; n]`.
-    Array(Ty<'tcx>, &'tcx ty::Const<'tcx>),
+    /// An array with the given length. Written as `[T; N]`.
+    Array(Ty<'tcx>, ty::Const<'tcx>),
 
     /// The pointee of an array slice. Written as `[T]`.
     Slice(Ty<'tcx>),
@@ -126,11 +131,12 @@ pub enum TyKind<'tcx> {
     Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability),
 
     /// The anonymous type of a function declaration/definition. Each
-    /// function has a unique type, which is output (for a function
-    /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
+    /// function has a unique type.
     ///
-    /// For example the type of `bar` here:
+    /// For the function `fn foo() -> i32 { 3 }` this type would be
+    /// shown to the user as `fn() -> i32 {foo}`.
     ///
+    /// For example the type of `bar` here:
     /// ```rust
     /// fn foo() -> i32 { 1 }
     /// let bar = foo; // bar: fn() -> i32 {foo}
@@ -139,6 +145,9 @@ pub enum TyKind<'tcx> {
 
     /// A pointer to a function. Written as `fn() -> i32`.
     ///
+    /// Note that both functions and closures start out as either
+    /// [FnDef] or [Closure] which can be then be coerced to this variant.
+    ///
     /// For example the type of `bar` here:
     ///
     /// ```rust
@@ -150,47 +159,92 @@ pub enum TyKind<'tcx> {
     /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
     Dynamic(&'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
 
-    /// The anonymous type of a closure. Used to represent the type of
-    /// `|a| a`.
+    /// The anonymous type of a closure. Used to represent the type of `|a| a`.
+    ///
+    /// Closure substs contain both the - potentially substituted - generic parameters
+    /// of its parent and some synthetic parameters. See the documentation for
+    /// [ClosureSubsts] for more details.
     Closure(DefId, SubstsRef<'tcx>),
 
     /// The anonymous type of a generator. Used to represent the type of
     /// `|a| yield a`.
+    ///
+    /// For more info about generator substs, visit the documentation for
+    /// [GeneratorSubsts].
     Generator(DefId, SubstsRef<'tcx>, hir::Movability),
 
     /// A type representing the types stored inside a generator.
-    /// This should only appear in GeneratorInteriors.
+    /// This should only appear as part of the [GeneratorSubsts].
+    ///
+    /// Note that the captured variables for generators are stored separately
+    /// using a tuple in the same way as for closures.
+    ///
+    /// Unlike upvars, the witness can reference lifetimes from
+    /// inside of the generator itself. To deal with them in
+    /// the type of the generator, we convert them to higher ranked
+    /// lifetimes bound by the witness itself.
+    ///
+    /// Looking at the following example, the witness for this generator
+    /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
+    ///
+    /// ```rust
+    /// |a| {
+    ///     let x = &vec![3];
+    ///     yield a;
+    ///     yield x[0];
+    /// }
+    /// ```
     GeneratorWitness(Binder<'tcx, &'tcx List<Ty<'tcx>>>),
 
     /// The never type `!`.
     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`.
     Projection(ProjectionTy<'tcx>),
 
     /// Opaque (`impl Trait`) type found in a return type.
+    ///
     /// The `DefId` comes either from
     /// * the `impl Trait` ast::Ty node,
     /// * or the `type Foo = impl Trait` declaration
-    /// The substitutions are for the generics of the function in question.
-    /// After typeck, the concrete type can be found in the `types` map.
+    ///
+    /// For RPIT the substitutions are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    ///
+    /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
     Opaque(DefId, SubstsRef<'tcx>),
 
     /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
     Param(ParamTy),
 
-    /// Bound type variable, used only when preparing a trait query.
+    /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`.
+    ///
+    /// For canonical queries, we replace inference variables with bound variables,
+    /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to
+    /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
+    /// back to inference variables in a new inference context when inside of the query.
+    ///
+    /// See the `rustc-dev-guide` for more details about
+    /// [higher-ranked trait bounds][1] and [canonical queries][2].
+    ///
+    /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+    /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
     Bound(ty::DebruijnIndex, BoundTy),
 
-    /// A placeholder type - universally quantified higher-ranked type.
+    /// A placeholder type, used during higher ranked subtyping to instantiate
+    /// bound variables.
     Placeholder(ty::PlaceholderType),
 
     /// A type variable used during type checking.
+    ///
+    /// Similar to placeholders, inference variables also live in a universe to
+    /// correctly deal with higher ranked types. Though unlike placeholders,
+    /// that universe is stored in the `InferCtxt` instead of directly
+    /// inside of the type.
     Infer(InferTy),
 
     /// A placeholder for a type which could not be computed; this is
@@ -231,7 +285,7 @@ pub fn article(&self) -> &'static str {
 ///   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
@@ -1340,7 +1394,24 @@ pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
     }
 }
 
-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
@@ -1348,6 +1419,9 @@ pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
 /// 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
@@ -1604,40 +1678,59 @@ pub fn item_def_id(&self) -> DefId {
 }
 
 /// 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 {
@@ -1695,8 +1788,8 @@ pub fn type_flags(&self) -> TypeFlags {
     /// 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),
@@ -1705,19 +1798,19 @@ pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId {
 }
 
 /// 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,
@@ -1725,32 +1818,32 @@ pub fn is_unit(&self) -> bool {
     }
 
     #[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,
@@ -1758,28 +1851,28 @@ pub fn ty_vid(&self) -> Option<ty::TyVid> {
     }
 
     #[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,
@@ -1787,7 +1880,7 @@ pub fn is_param(&self, index: u32) -> bool {
     }
 
     #[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,
@@ -1795,27 +1888,27 @@ pub fn is_slice(&self) -> bool {
     }
 
     #[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");
@@ -1830,7 +1923,7 @@ pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
                         // 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).
@@ -1842,12 +1935,12 @@ pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
     }
 
     #[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, .. })
@@ -1857,7 +1950,7 @@ pub fn is_mutable_ptr(&self) -> bool {
 
     /// 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,
@@ -1865,18 +1958,18 @@ pub fn ref_mutability(&self) -> Option<hir::Mutability> {
     }
 
     #[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,
@@ -1884,7 +1977,7 @@ pub fn is_box(&self) -> bool {
     }
 
     /// 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),
@@ -1895,7 +1988,7 @@ pub fn boxed_ty(&self) -> Ty<'tcx> {
     /// (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
@@ -1911,99 +2004,117 @@ pub fn is_scalar(&self) -> bool {
 
     /// 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,
@@ -2019,22 +2130,22 @@ pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
     }
 
     #[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,
@@ -2043,18 +2154,9 @@ pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> {
 
     /// Iterates over tuple fields.
     /// Panics when called on anything but a tuple.
-    pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item = 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>> {
+    pub fn tuple_fields(self) -> &'tcx List<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"),
         }
     }
@@ -2063,7 +2165,7 @@ pub fn tuple_element_ty(&self, i: usize) -> Option<Ty<'tcx>> {
     //
     // 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, _) => {
@@ -2079,7 +2181,7 @@ pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
     // 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>> {
@@ -2100,7 +2202,7 @@ pub fn discriminant_for_variant(
     }
 
     /// 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),
@@ -2144,7 +2246,7 @@ pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> 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> {
@@ -2205,7 +2307,7 @@ pub fn ptr_metadata_ty(
     /// 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),
@@ -2234,7 +2336,7 @@ pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
     /// 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(_)
@@ -2255,7 +2357,7 @@ pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
 
             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(),