about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-23 10:29:11 +0100
committerGitHub <noreply@github.com>2020-03-23 10:29:11 +0100
commitbee074f032970fd1b59650c04a70e75eeee9c63b (patch)
treefae855037a249c1191dfca9c29ee8e9261790b85 /src/librustc
parent906b39958322c54b76de4f301976e7753777be4e (diff)
parentd9a15ccd976bc8a4a79c99fbf68892c2bbdfffec (diff)
Rollup merge of #69968 - eddyb:tupled-closure-captures, r=nikomatsakis
rustc: keep upvars tupled in {Closure,Generator}Substs.

Previously, each closure/generator capture's (aka "upvar") type was tracked as one "synthetic" type parameter in the closure/generator substs, and figuring out where the parent `fn`'s generics end and the synthetics start involved slicing at `tcx.generics_of(def_id).parent_count`.

Needing to query `generics_of` limited @davidtwco (who wants to compute some `TypeFlags` differently for parent generics vs upvars, and `TyCtxt` is not available there), which is how I got started on this, but it's also possible that the `generics_of` queries are slowing down `{Closure,Generator}Substs` methods.

To give an example, for a `foo::<T, U>::{closure#0}` with captures `x: X` and `y: Y`, substs are:
* before this PR: `[T, U, /*kind*/, /*signature*/, X, Y]`
* after this PR: `[T, U, /*kind*/, /*signature*/, (X, Y)]`

You can see that, with this PR, no matter how many captures, the last 3 entries in the substs (or 5 for a generator) are always the "synthetic" ones, with the last one being the tuple of capture types.

r? @nikomatsakis cc @Zoxc
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/traits/query.rs4
-rw-r--r--src/librustc/ty/instance.rs4
-rw-r--r--src/librustc/ty/layout.rs20
-rw-r--r--src/librustc/ty/outlives.rs8
-rw-r--r--src/librustc/ty/print/pretty.rs87
-rw-r--r--src/librustc/ty/sty.rs191
-rw-r--r--src/librustc/ty/util.rs2
7 files changed, 160 insertions, 156 deletions
diff --git a/src/librustc/traits/query.rs b/src/librustc/traits/query.rs
index c9055182620..67f4b15f919 100644
--- a/src/librustc/traits/query.rs
+++ b/src/librustc/traits/query.rs
@@ -229,8 +229,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         // (T1..Tn) and closures have same properties as T1..Tn --
         // check if *any* of those are trivial.
         ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
-        ty::Closure(def_id, ref substs) => {
-            substs.as_closure().upvar_tys(def_id, tcx).all(|t| trivial_dropck_outlives(tcx, t))
+        ty::Closure(_, ref substs) => {
+            substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
         }
 
         ty::Adt(def, _) => {
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 46372701a92..ac49feaf8c2 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -341,7 +341,7 @@ impl<'tcx> Instance<'tcx> {
         substs: ty::SubstsRef<'tcx>,
         requested_kind: ty::ClosureKind,
     ) -> Instance<'tcx> {
-        let actual_kind = substs.as_closure().kind(def_id, tcx);
+        let actual_kind = substs.as_closure().kind();
 
         match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
             Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs),
@@ -372,7 +372,7 @@ impl<'tcx> Instance<'tcx> {
 
         let self_ty = tcx.mk_closure(closure_did, substs);
 
-        let sig = substs.as_closure().sig(closure_did, tcx);
+        let sig = substs.as_closure().sig();
         let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
         assert_eq!(sig.inputs().len(), 1);
         let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index d66fcd3a20d..c54360e0393 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -628,8 +628,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
             ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?,
 
-            ty::Closure(def_id, ref substs) => {
-                let tys = substs.as_closure().upvar_tys(def_id, tcx);
+            ty::Closure(_, ref substs) => {
+                let tys = substs.as_closure().upvar_tys();
                 univariant(
                     &tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(),
@@ -1402,7 +1402,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
         // Build a prefix layout, including "promoting" all ineligible
         // locals as part of the prefix. We compute the layout of all of
         // these fields at once to get optimal packing.
-        let discr_index = substs.as_generator().prefix_tys(def_id, tcx).count();
+        let discr_index = substs.as_generator().prefix_tys().count();
 
         // `info.variant_fields` already accounts for the reserved variants, so no need to add them.
         let max_discr = (info.variant_fields.len() - 1) as u128;
@@ -1419,7 +1419,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             .map(|ty| self.layout_of(ty));
         let prefix_layouts = substs
             .as_generator()
-            .prefix_tys(def_id, tcx)
+            .prefix_tys()
             .map(|ty| self.layout_of(ty))
             .chain(iter::once(Ok(discr_layout)))
             .chain(promoted_layouts)
@@ -2095,9 +2095,7 @@ where
             ty::Str => tcx.types.u8,
 
             // Tuples, generators and closures.
-            ty::Closure(def_id, ref substs) => {
-                substs.as_closure().upvar_tys(def_id, tcx).nth(i).unwrap()
-            }
+            ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().nth(i).unwrap(),
 
             ty::Generator(def_id, ref substs, _) => match this.variants {
                 Variants::Single { index } => substs
@@ -2111,7 +2109,7 @@ where
                     if i == discr_index {
                         return discr_layout(discr);
                     }
-                    substs.as_generator().prefix_tys(def_id, tcx).nth(i).unwrap()
+                    substs.as_generator().prefix_tys().nth(i).unwrap()
                 }
             },
 
@@ -2298,7 +2296,7 @@ impl<'tcx> ty::Instance<'tcx> {
                 sig
             }
             ty::Closure(def_id, substs) => {
-                let sig = substs.as_closure().sig(def_id, tcx);
+                let sig = substs.as_closure().sig();
 
                 let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
                 sig.map_bound(|sig| tcx.mk_fn_sig(
@@ -2309,8 +2307,8 @@ impl<'tcx> ty::Instance<'tcx> {
                     sig.abi
                 ))
             }
-            ty::Generator(def_id, substs, _) => {
-                let sig = substs.as_generator().poly_sig(def_id, tcx);
+            ty::Generator(_, substs, _) => {
+                let sig = substs.as_generator().poly_sig();
 
                 let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
                 let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index b397a2c80d5..9dd96f2f2b5 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -61,15 +61,15 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
     // in the `subtys` iterator (e.g., when encountering a
     // projection).
     match ty.kind {
-            ty::Closure(def_id, ref substs) => {
-                for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) {
+            ty::Closure(_, ref substs) => {
+                for upvar_ty in substs.as_closure().upvar_tys() {
                     compute_components(tcx, upvar_ty, out);
                 }
             }
 
-            ty::Generator(def_id, ref substs, _) => {
+            ty::Generator(_, ref substs, _) => {
                 // Same as the closure case
-                for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) {
+                for upvar_ty in substs.as_generator().upvar_tys() {
                     compute_components(tcx, upvar_ty, out);
                 }
 
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 8fbb9f0891a..3a95c573ca3 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -617,8 +617,6 @@ pub trait PrettyPrinter<'tcx>:
             }
             ty::Str => p!(write("str")),
             ty::Generator(did, substs, movability) => {
-                let upvar_tys = substs.as_generator().upvar_tys(did, self.tcx());
-                let witness = substs.as_generator().witness(did, self.tcx());
                 match movability {
                     hir::Movability::Movable => p!(write("[generator")),
                     hir::Movability::Static => p!(write("[static generator")),
@@ -627,31 +625,47 @@ pub trait PrettyPrinter<'tcx>:
                 // FIXME(eddyb) should use `def_span`.
                 if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) {
                     p!(write("@{:?}", self.tcx().hir().span(hir_id)));
-                    let mut sep = " ";
-                    for (&var_id, upvar_ty) in
-                        self.tcx().upvars(did).as_ref().iter().flat_map(|v| v.keys()).zip(upvar_tys)
-                    {
-                        p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
-                        sep = ", ";
+
+                    if substs.as_generator().is_valid() {
+                        let upvar_tys = substs.as_generator().upvar_tys();
+                        let mut sep = " ";
+                        for (&var_id, upvar_ty) in self
+                            .tcx()
+                            .upvars(did)
+                            .as_ref()
+                            .iter()
+                            .flat_map(|v| v.keys())
+                            .zip(upvar_tys)
+                        {
+                            p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
+                            sep = ", ";
+                        }
                     }
                 } else {
                     // Cross-crate closure types should only be
                     // visible in codegen bug reports, I imagine.
                     p!(write("@{:?}", did));
-                    let mut sep = " ";
-                    for (index, upvar_ty) in upvar_tys.enumerate() {
-                        p!(write("{}{}:", sep, index), print(upvar_ty));
-                        sep = ", ";
+
+                    if substs.as_generator().is_valid() {
+                        let upvar_tys = substs.as_generator().upvar_tys();
+                        let mut sep = " ";
+                        for (index, upvar_ty) in upvar_tys.enumerate() {
+                            p!(write("{}{}:", sep, index), print(upvar_ty));
+                            sep = ", ";
+                        }
                     }
                 }
 
-                p!(write(" "), print(witness), write("]"))
+                if substs.as_generator().is_valid() {
+                    p!(write(" "), print(substs.as_generator().witness()));
+                }
+
+                p!(write("]"))
             }
             ty::GeneratorWitness(types) => {
                 p!(in_binder(&types));
             }
             ty::Closure(did, substs) => {
-                let upvar_tys = substs.as_closure().upvar_tys(did, self.tcx());
                 p!(write("[closure"));
 
                 // FIXME(eddyb) should use `def_span`.
@@ -661,30 +675,43 @@ pub trait PrettyPrinter<'tcx>:
                     } else {
                         p!(write("@{:?}", self.tcx().hir().span(hir_id)));
                     }
-                    let mut sep = " ";
-                    for (&var_id, upvar_ty) in
-                        self.tcx().upvars(did).as_ref().iter().flat_map(|v| v.keys()).zip(upvar_tys)
-                    {
-                        p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
-                        sep = ", ";
+
+                    if substs.as_closure().is_valid() {
+                        let upvar_tys = substs.as_closure().upvar_tys();
+                        let mut sep = " ";
+                        for (&var_id, upvar_ty) in self
+                            .tcx()
+                            .upvars(did)
+                            .as_ref()
+                            .iter()
+                            .flat_map(|v| v.keys())
+                            .zip(upvar_tys)
+                        {
+                            p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
+                            sep = ", ";
+                        }
                     }
                 } else {
                     // Cross-crate closure types should only be
                     // visible in codegen bug reports, I imagine.
                     p!(write("@{:?}", did));
-                    let mut sep = " ";
-                    for (index, upvar_ty) in upvar_tys.enumerate() {
-                        p!(write("{}{}:", sep, index), print(upvar_ty));
-                        sep = ", ";
+
+                    if substs.as_closure().is_valid() {
+                        let upvar_tys = substs.as_closure().upvar_tys();
+                        let mut sep = " ";
+                        for (index, upvar_ty) in upvar_tys.enumerate() {
+                            p!(write("{}{}:", sep, index), print(upvar_ty));
+                            sep = ", ";
+                        }
                     }
                 }
 
-                if self.tcx().sess.verbose() {
-                    p!(write(
-                        " closure_kind_ty={:?} closure_sig_as_fn_ptr_ty={:?}",
-                        substs.as_closure().kind_ty(did, self.tcx()),
-                        substs.as_closure().sig_as_fn_ptr_ty(did, self.tcx())
-                    ));
+                if self.tcx().sess.verbose() && substs.as_closure().is_valid() {
+                    p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty()));
+                    p!(
+                        write(" closure_sig_as_fn_ptr_ty="),
+                        print(substs.as_closure().sig_as_fn_ptr_ty())
+                    );
                 }
 
                 p!(write("]"))
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 00310ef9b31..096f63fdf2e 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -11,7 +11,7 @@ use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::Scalar;
 use crate::mir::Promoted;
 use crate::ty::layout::VariantIdx;
-use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
+use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::{
     self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
 };
@@ -260,15 +260,11 @@ static_assert_size!(TyKind<'_>, 24);
 
 /// A closure can be modeled as a struct that looks like:
 ///
-///     struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> {
-///         upvar0: U0,
-///         ...
-///         upvark: Uk
-///     }
+///     struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U);
 ///
 /// where:
 ///
-/// - 'l0...'li and T0...Tj are the lifetime and type parameters
+/// - 'l0...'li and T0...Tj are the generic parameters
 ///   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
@@ -277,9 +273,9 @@ static_assert_size!(TyKind<'_>, 24);
 ///   type. For example, `fn(u32, u32) -> u32` would mean that the closure
 ///   implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
 ///   specified above.
-/// - U0...Uk are type parameters representing the types of its upvars
-///   (borrowed, if appropriate; that is, if Ui represents a by-ref upvar,
-///    and the up-var has the type `Foo`, then `Ui = &Foo`).
+/// - U is a type parameter representing the types of its upvars, tupled up
+///   (borrowed, if appropriate; that is, if an U field represents a by-ref upvar,
+///    and the up-var has the type `Foo`, then that field of U will be `&Foo`).
 ///
 /// So, for example, given this function:
 ///
@@ -289,9 +285,7 @@ static_assert_size!(TyKind<'_>, 24);
 ///
 /// the type of the closure would be something like:
 ///
-///     struct Closure<'a, T, U0> {
-///         data: U0
-///     }
+///     struct Closure<'a, T, U>(...U);
 ///
 /// Note that the type of the upvar is not specified in the struct.
 /// You may wonder how the impl would then be able to use the upvar,
@@ -299,7 +293,7 @@ static_assert_size!(TyKind<'_>, 24);
 /// (conceptually) not fully generic over Closure but rather tied to
 /// instances with the expected upvar types:
 ///
-///     impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> {
+///     impl<'b, 'a, T> FnMut() for Closure<'a, T, (&'b mut &'a mut T,)> {
 ///         ...
 ///     }
 ///
@@ -308,7 +302,7 @@ static_assert_size!(TyKind<'_>, 24);
 /// (Here, I am assuming that `data` is mut-borrowed.)
 ///
 /// Now, the last question you may ask is: Why include the upvar types
-/// as extra type parameters? The reason for this design is that the
+/// in an extra type parameter? The reason for this design is that the
 /// upvar types can reference lifetimes that are internal to the
 /// creating function. In my example above, for example, the lifetime
 /// `'b` represents the scope of the closure itself; this is some
@@ -360,7 +354,7 @@ static_assert_size!(TyKind<'_>, 24);
 #[derive(Copy, Clone, Debug, TypeFoldable)]
 pub struct ClosureSubsts<'tcx> {
     /// Lifetime and type parameters from the enclosing function,
-    /// concatenated with the types of the upvars.
+    /// concatenated with a tuple containing the types of the upvars.
     ///
     /// These are separated out because codegen wants to pass them around
     /// when monomorphizing.
@@ -370,52 +364,52 @@ pub struct ClosureSubsts<'tcx> {
 /// Struct returned by `split()`. Note that these are subslices of the
 /// parent slice and not canonical substs themselves.
 struct SplitClosureSubsts<'tcx> {
-    closure_kind_ty: Ty<'tcx>,
-    closure_sig_as_fn_ptr_ty: Ty<'tcx>,
-    upvar_kinds: &'tcx [GenericArg<'tcx>],
+    closure_kind_ty: GenericArg<'tcx>,
+    closure_sig_as_fn_ptr_ty: GenericArg<'tcx>,
+    tupled_upvars_ty: GenericArg<'tcx>,
 }
 
 impl<'tcx> ClosureSubsts<'tcx> {
     /// Divides the closure substs into their respective
     /// components. Single source of truth with respect to the
     /// ordering.
-    fn split(self, def_id: DefId, tcx: TyCtxt<'_>) -> SplitClosureSubsts<'tcx> {
-        let generics = tcx.generics_of(def_id);
-        let parent_len = generics.parent_count;
-        SplitClosureSubsts {
-            closure_kind_ty: self.substs.type_at(parent_len),
-            closure_sig_as_fn_ptr_ty: self.substs.type_at(parent_len + 1),
-            upvar_kinds: &self.substs[parent_len + 2..],
+    fn split(self) -> SplitClosureSubsts<'tcx> {
+        match self.substs[..] {
+            [.., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
+                SplitClosureSubsts { closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty }
+            }
+            _ => bug!("closure substs missing synthetics"),
         }
     }
 
+    /// Returns `true` only if enough of the synthetic types are known to
+    /// allow using all of the methods on `ClosureSubsts` without panicking.
+    ///
+    /// Used primarily by `ty::print::pretty` to be able to handle closure
+    /// types that haven't had their synthetic types substituted in.
+    pub fn is_valid(self) -> bool {
+        self.substs.len() >= 3 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_))
+    }
+
     #[inline]
-    pub fn upvar_tys(
-        self,
-        def_id: DefId,
-        tcx: TyCtxt<'_>,
-    ) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
-        let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
-        upvar_kinds.iter().map(|t| {
-            if let GenericArgKind::Type(ty) = t.unpack() {
-                ty
-            } else {
-                bug!("upvar should be type")
-            }
-        })
+    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+        self.split().tupled_upvars_ty.expect_ty().tuple_fields()
     }
 
     /// Returns the closure kind for this closure; may return a type
     /// variable during inference. To get the closure kind during
-    /// inference, use `infcx.closure_kind(def_id, substs)`.
-    pub fn kind_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
-        self.split(def_id, tcx).closure_kind_ty
+    /// inference, use `infcx.closure_kind(substs)`.
+    pub fn kind_ty(self) -> Ty<'tcx> {
+        self.split().closure_kind_ty.expect_ty()
     }
 
     /// Returns the `fn` pointer type representing the closure signature for this
     /// closure.
-    pub fn sig_as_fn_ptr_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
-        self.split(def_id, tcx).closure_sig_as_fn_ptr_ty
+    // FIXME(eddyb) this should be unnecessary, as the shallowly resolved
+    // type is known at the time of the creation of `ClosureSubsts`,
+    // see `rustc_typeck::check::closure`.
+    pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> {
+        self.split().closure_sig_as_fn_ptr_ty.expect_ty()
     }
 
     /// Returns the closure kind for this closure; only usable outside
@@ -423,13 +417,13 @@ impl<'tcx> ClosureSubsts<'tcx> {
     /// there are no type variables.
     ///
     /// If you have an inference context, use `infcx.closure_kind()`.
-    pub fn kind(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::ClosureKind {
-        self.split(def_id, tcx).closure_kind_ty.to_opt_closure_kind().unwrap()
+    pub fn kind(self) -> ty::ClosureKind {
+        self.kind_ty().to_opt_closure_kind().unwrap()
     }
 
     /// Extracts the signature from the closure.
-    pub fn sig(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
-        let ty = self.sig_as_fn_ptr_ty(def_id, tcx);
+    pub fn sig(self) -> ty::PolyFnSig<'tcx> {
+        let ty = self.sig_as_fn_ptr_ty();
         match ty.kind {
             ty::FnPtr(sig) => sig,
             _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind),
@@ -444,64 +438,59 @@ pub struct GeneratorSubsts<'tcx> {
 }
 
 struct SplitGeneratorSubsts<'tcx> {
-    resume_ty: Ty<'tcx>,
-    yield_ty: Ty<'tcx>,
-    return_ty: Ty<'tcx>,
-    witness: Ty<'tcx>,
-    upvar_kinds: &'tcx [GenericArg<'tcx>],
+    resume_ty: GenericArg<'tcx>,
+    yield_ty: GenericArg<'tcx>,
+    return_ty: GenericArg<'tcx>,
+    witness: GenericArg<'tcx>,
+    tupled_upvars_ty: GenericArg<'tcx>,
 }
 
 impl<'tcx> GeneratorSubsts<'tcx> {
-    fn split(self, def_id: DefId, tcx: TyCtxt<'_>) -> SplitGeneratorSubsts<'tcx> {
-        let generics = tcx.generics_of(def_id);
-        let parent_len = generics.parent_count;
-        SplitGeneratorSubsts {
-            resume_ty: self.substs.type_at(parent_len),
-            yield_ty: self.substs.type_at(parent_len + 1),
-            return_ty: self.substs.type_at(parent_len + 2),
-            witness: self.substs.type_at(parent_len + 3),
-            upvar_kinds: &self.substs[parent_len + 4..],
+    fn split(self) -> SplitGeneratorSubsts<'tcx> {
+        match self.substs[..] {
+            [.., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
+                SplitGeneratorSubsts { resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty }
+            }
+            _ => bug!("generator substs missing synthetics"),
         }
     }
 
+    /// Returns `true` only if enough of the synthetic types are known to
+    /// allow using all of the methods on `GeneratorSubsts` without panicking.
+    ///
+    /// Used primarily by `ty::print::pretty` to be able to handle generator
+    /// types that haven't had their synthetic types substituted in.
+    pub fn is_valid(self) -> bool {
+        self.substs.len() >= 5 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_))
+    }
+
     /// This describes the types that can be contained in a generator.
     /// It will be a type variable initially and unified in the last stages of typeck of a body.
     /// It contains a tuple of all the types that could end up on a generator frame.
     /// The state transformation MIR pass may only produce layouts which mention types
     /// in this tuple. Upvars are not counted here.
-    pub fn witness(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
-        self.split(def_id, tcx).witness
+    pub fn witness(self) -> Ty<'tcx> {
+        self.split().witness.expect_ty()
     }
 
     #[inline]
-    pub fn upvar_tys(
-        self,
-        def_id: DefId,
-        tcx: TyCtxt<'_>,
-    ) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
-        let SplitGeneratorSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
-        upvar_kinds.iter().map(|t| {
-            if let GenericArgKind::Type(ty) = t.unpack() {
-                ty
-            } else {
-                bug!("upvar should be type")
-            }
-        })
+    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+        self.split().tupled_upvars_ty.expect_ty().tuple_fields()
     }
 
     /// Returns the type representing the resume type of the generator.
-    pub fn resume_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
-        self.split(def_id, tcx).resume_ty
+    pub fn resume_ty(self) -> Ty<'tcx> {
+        self.split().resume_ty.expect_ty()
     }
 
     /// Returns the type representing the yield type of the generator.
-    pub fn yield_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
-        self.split(def_id, tcx).yield_ty
+    pub fn yield_ty(self) -> Ty<'tcx> {
+        self.split().yield_ty.expect_ty()
     }
 
     /// Returns the type representing the return type of the generator.
-    pub fn return_ty(self, def_id: DefId, tcx: TyCtxt<'_>) -> Ty<'tcx> {
-        self.split(def_id, tcx).return_ty
+    pub fn return_ty(self) -> Ty<'tcx> {
+        self.split().return_ty.expect_ty()
     }
 
     /// Returns the "generator signature", which consists of its yield
@@ -510,17 +499,17 @@ impl<'tcx> GeneratorSubsts<'tcx> {
     /// N.B., some bits of the code prefers to see this wrapped in a
     /// binder, but it never contains bound regions. Probably this
     /// function should be removed.
-    pub fn poly_sig(self, def_id: DefId, tcx: TyCtxt<'_>) -> PolyGenSig<'tcx> {
-        ty::Binder::dummy(self.sig(def_id, tcx))
+    pub fn poly_sig(self) -> PolyGenSig<'tcx> {
+        ty::Binder::dummy(self.sig())
     }
 
     /// Returns the "generator signature", which consists of its resume, yield
     /// and return types.
-    pub fn sig(self, def_id: DefId, tcx: TyCtxt<'_>) -> GenSig<'tcx> {
+    pub fn sig(self) -> GenSig<'tcx> {
         ty::GenSig {
-            resume_ty: self.resume_ty(def_id, tcx),
-            yield_ty: self.yield_ty(def_id, tcx),
-            return_ty: self.return_ty(def_id, tcx),
+            resume_ty: self.resume_ty(),
+            yield_ty: self.yield_ty(),
+            return_ty: self.return_ty(),
         }
     }
 }
@@ -612,8 +601,8 @@ impl<'tcx> GeneratorSubsts<'tcx> {
     /// This is the types of the fields of a generator which are not stored in a
     /// variant.
     #[inline]
-    pub fn prefix_tys(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = Ty<'tcx>> {
-        self.upvar_tys(def_id, tcx)
+    pub fn prefix_tys(self) -> impl Iterator<Item = Ty<'tcx>> {
+        self.upvar_tys()
     }
 }
 
@@ -625,22 +614,12 @@ pub enum UpvarSubsts<'tcx> {
 
 impl<'tcx> UpvarSubsts<'tcx> {
     #[inline]
-    pub fn upvar_tys(
-        self,
-        def_id: DefId,
-        tcx: TyCtxt<'tcx>,
-    ) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
-        let upvar_kinds = match self {
-            UpvarSubsts::Closure(substs) => substs.as_closure().split(def_id, tcx).upvar_kinds,
-            UpvarSubsts::Generator(substs) => substs.as_generator().split(def_id, tcx).upvar_kinds,
+    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+        let tupled_upvars_ty = match self {
+            UpvarSubsts::Closure(substs) => substs.as_closure().split().tupled_upvars_ty,
+            UpvarSubsts::Generator(substs) => substs.as_generator().split().tupled_upvars_ty,
         };
-        upvar_kinds.iter().map(|t| {
-            if let GenericArgKind::Type(ty) = t.unpack() {
-                ty
-            } else {
-                bug!("upvar should be type")
-            }
-        })
+        tupled_upvars_ty.expect_ty().tuple_fields()
     }
 }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 69daa2da1fd..1f512f1dde7 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -502,7 +502,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> Option<ty::Binder<Ty<'tcx>>> {
         let closure_ty = self.mk_closure(closure_def_id, closure_substs);
         let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
-        let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self);
+        let closure_kind_ty = closure_substs.as_closure().kind_ty();
         let closure_kind = closure_kind_ty.to_opt_closure_kind()?;
         let env_ty = match closure_kind {
             ty::ClosureKind::Fn => self.mk_imm_ref(self.mk_region(env_region), closure_ty),