about summary refs log tree commit diff
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
parent906b39958322c54b76de4f301976e7753777be4e (diff)
parentd9a15ccd976bc8a4a79c99fbf68892c2bbdfffec (diff)
downloadrust-bee074f032970fd1b59650c04a70e75eeee9c63b.tar.gz
rust-bee074f032970fd1b59650c04a70e75eeee9c63b.zip
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
-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
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs4
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs8
-rw-r--r--src/librustc_infer/infer/mod.rs8
-rw-r--r--src/librustc_infer/infer/type_variable.rs1
-rw-r--r--src/librustc_metadata/rmeta/encoder.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs6
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/region_errors.rs5
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/region_name.rs4
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/var_name.rs4
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs26
-rw-r--r--src/librustc_mir/borrow_check/universal_regions.rs20
-rw-r--r--src/librustc_mir/shim.rs4
-rw-r--r--src/librustc_mir/transform/generator.rs4
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs8
-rw-r--r--src/librustc_mir_build/build/mod.rs12
-rw-r--r--src/librustc_mir_build/hair/cx/expr.rs4
-rw-r--r--src/librustc_trait_selection/opaque_types.rs27
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs2
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs4
-rw-r--r--src/librustc_trait_selection/traits/fulfill.rs4
-rw-r--r--src/librustc_trait_selection/traits/project.rs5
-rw-r--r--src/librustc_trait_selection/traits/query/dropck_outlives.rs4
-rw-r--r--src/librustc_trait_selection/traits/select.rs41
-rw-r--r--src/librustc_trait_selection/traits/wf.rs4
-rw-r--r--src/librustc_traits/dropck_outlives.rs10
-rw-r--r--src/librustc_ty/needs_drop.rs4
-rw-r--r--src/librustc_typeck/check/callee.rs8
-rw-r--r--src/librustc_typeck/check/closure.rs70
-rw-r--r--src/librustc_typeck/check/coercion.rs10
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/check/regionck.rs4
-rw-r--r--src/librustc_typeck/check/upvar.rs8
-rw-r--r--src/librustc_typeck/collect.rs20
-rw-r--r--src/test/ui/issues/issue-22638.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument-callee.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr6
-rw-r--r--src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr3
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr1
-rw-r--r--src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr1
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr4
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr4
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr5
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr5
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr8
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr1
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr4
65 files changed, 356 insertions, 367 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),
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index c867d8cf3c4..d7a0acb1339 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -663,7 +663,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp
             MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
         }
         ty::Closure(def_id, substs) => {
-            let upvar_tys: Vec<_> = substs.as_closure().upvar_tys(def_id, cx.tcx).collect();
+            let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
             let containing_scope = get_namespace_for_item(cx, def_id);
             prepare_tuple_metadata(
                 cx,
@@ -678,7 +678,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp
         ty::Generator(def_id, substs, _) => {
             let upvar_tys: Vec<_> = substs
                 .as_generator()
-                .prefix_tys(def_id, cx.tcx)
+                .prefix_tys()
                 .map(|t| cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
                 .collect();
             prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span, upvar_tys)
diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index ea8b4f41888..fcbe938a8c7 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -277,8 +277,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
 
         let ty_msg = match local_visitor.found_ty {
-            Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => {
-                let fn_sig = substs.as_closure().sig(*def_id, self.tcx);
+            Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
+                let fn_sig = substs.as_closure().sig();
                 let args = closure_args(&fn_sig);
                 let ret = fn_sig.output().skip_binder().to_string();
                 format!(" for the closure `fn({}) -> {}`", args, ret)
@@ -311,8 +311,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         );
 
         let suffix = match local_visitor.found_ty {
-            Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => {
-                let fn_sig = substs.as_closure().sig(*def_id, self.tcx);
+            Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
+                let fn_sig = substs.as_closure().sig();
                 let ret = fn_sig.output().skip_binder().to_string();
 
                 if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure {
diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs
index fbacc31b117..fb00fbe2826 100644
--- a/src/librustc_infer/infer/mod.rs
+++ b/src/librustc_infer/infer/mod.rs
@@ -1496,12 +1496,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Obtains the latest type of the given closure; this may be a
     /// closure in the current function, in which case its
     /// `ClosureKind` may not yet be known.
-    pub fn closure_kind(
-        &self,
-        closure_def_id: DefId,
-        closure_substs: SubstsRef<'tcx>,
-    ) -> Option<ty::ClosureKind> {
-        let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self.tcx);
+    pub fn closure_kind(&self, closure_substs: SubstsRef<'tcx>) -> Option<ty::ClosureKind> {
+        let closure_kind_ty = closure_substs.as_closure().kind_ty();
         let closure_kind_ty = self.shallow_resolve(closure_kind_ty);
         closure_kind_ty.to_opt_closure_kind()
     }
diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs
index b59c5606691..53bc70a5344 100644
--- a/src/librustc_infer/infer/type_variable.rs
+++ b/src/librustc_infer/infer/type_variable.rs
@@ -54,6 +54,7 @@ pub enum TypeVariableOriginKind {
 
     /// One of the upvars or closure kind parameters in a `ClosureSubsts`
     /// (before it has been determined).
+    // FIXME(eddyb) distinguish upvar inference variables from the rest.
     ClosureSynthetic,
     SubstitutionPlaceholder,
     AutoDeref,
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index a3803bc0707..52124fd3abb 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -1320,7 +1320,7 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
         self.encode_item_type(def_id);
         if let ty::Closure(def_id, substs) = ty.kind {
-            record!(self.per_def.fn_sig[def_id] <- substs.as_closure().sig(def_id, self.tcx));
+            record!(self.per_def.fn_sig[def_id] <- substs.as_closure().sig());
         }
         self.encode_generics(def_id);
         self.encode_optimized_mir(def_id);
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index c545b6df70c..27a86169397 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -1682,10 +1682,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 // If a closure captured our `target` and then assigned
                                 // into a place then we should annotate the closure in
                                 // case it ends up being assigned into the return place.
-                                annotated_closure = self.annotate_fn_sig(
-                                    *def_id,
-                                    substs.as_closure().sig(*def_id, self.infcx.tcx),
-                                );
+                                annotated_closure =
+                                    self.annotate_fn_sig(*def_id, substs.as_closure().sig());
                                 debug!(
                                     "annotate_argument_and_return_for_borrow: \
                                      annotated_closure={:?} assigned_from_local={:?} \
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index 7b65a5a1098..83bc9849caf 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -333,7 +333,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             ty::Closure(def_id, closure_substs)
                 if def_id == self.mir_def_id && upvar_field.is_some() =>
             {
-                let closure_kind_ty = closure_substs.as_closure().kind_ty(def_id, self.infcx.tcx);
+                let closure_kind_ty = closure_substs.as_closure().kind_ty();
                 let closure_kind = closure_kind_ty.to_opt_closure_kind();
                 let capture_description = match closure_kind {
                     Some(ty::ClosureKind::Fn) => "captured variable in an `Fn` closure",
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index 494b6421fd5..93800d2a2b3 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -135,11 +135,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
         if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
             if let ty::BoundRegion::BrEnv = free_region.bound_region {
-                if let DefiningTy::Closure(def_id, substs) =
+                if let DefiningTy::Closure(_, substs) =
                     self.regioncx.universal_regions().defining_ty
                 {
-                    return substs.as_closure().kind(def_id, self.infcx.tcx)
-                        == ty::ClosureKind::FnMut;
+                    return substs.as_closure().kind() == ty::ClosureKind::FnMut;
                 }
             }
         }
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
index d1d0ba215e0..164125a145b 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
@@ -245,7 +245,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         .expect("non-local mir");
                     let def_ty = self.regioncx.universal_regions().defining_ty;
 
-                    if let DefiningTy::Closure(def_id, substs) = def_ty {
+                    if let DefiningTy::Closure(_, substs) = def_ty {
                         let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
                             tcx.hir().expect_expr(mir_hir_id).kind
                         {
@@ -255,7 +255,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         };
                         let region_name = self.synthesize_region_name();
 
-                        let closure_kind_ty = substs.as_closure().kind_ty(def_id, tcx);
+                        let closure_kind_ty = substs.as_closure().kind_ty();
                         let note = match closure_kind_ty.to_opt_closure_kind() {
                             Some(ty::ClosureKind::Fn) => {
                                 "closure implements `Fn`, so references to captured variables \
diff --git a/src/librustc_mir/borrow_check/diagnostics/var_name.rs b/src/librustc_mir/borrow_check/diagnostics/var_name.rs
index 5f3585ce8b1..c4933bedc22 100644
--- a/src/librustc_mir/borrow_check/diagnostics/var_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/var_name.rs
@@ -35,7 +35,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Search the upvars (if any) to find one that references fr. Return its index.
     crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option<usize> {
         let upvar_index =
-            self.universal_regions().defining_ty.upvar_tys(tcx).position(|upvar_ty| {
+            self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
                 debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
                 tcx.any_free_region_meets(&upvar_ty, |r| {
                     let r = r.to_region_vid();
@@ -44,7 +44,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 })
             })?;
 
-        let upvar_ty = self.universal_regions().defining_ty.upvar_tys(tcx).nth(upvar_index);
+        let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index);
 
         debug!(
             "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 521861624cb..52fc48806fb 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -757,21 +757,21 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 ty::Adt(adt_def, substs) if !adt_def.is_enum() => {
                     (&adt_def.variants[VariantIdx::new(0)], substs)
                 }
-                ty::Closure(def_id, substs) => {
-                    return match substs.as_closure().upvar_tys(def_id, tcx).nth(field.index()) {
+                ty::Closure(_, substs) => {
+                    return match substs.as_closure().upvar_tys().nth(field.index()) {
                         Some(ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
-                            field_count: substs.as_closure().upvar_tys(def_id, tcx).count(),
+                            field_count: substs.as_closure().upvar_tys().count(),
                         }),
                     };
                 }
-                ty::Generator(def_id, substs, _) => {
+                ty::Generator(_, substs, _) => {
                     // Only prefix fields (upvars and current state) are
                     // accessible without a variant index.
-                    return match substs.as_generator().prefix_tys(def_id, tcx).nth(field.index()) {
+                    return match substs.as_generator().prefix_tys().nth(field.index()) {
                         Some(ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
-                            field_count: substs.as_generator().prefix_tys(def_id, tcx).count(),
+                            field_count: substs.as_generator().prefix_tys().count(),
                         }),
                     };
                 }
@@ -1946,22 +1946,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
                 }
             }
-            AggregateKind::Closure(def_id, substs) => {
-                match substs.as_closure().upvar_tys(def_id, tcx).nth(field_index) {
+            AggregateKind::Closure(_, substs) => {
+                match substs.as_closure().upvar_tys().nth(field_index) {
                     Some(ty) => Ok(ty),
                     None => Err(FieldAccessError::OutOfRange {
-                        field_count: substs.as_closure().upvar_tys(def_id, tcx).count(),
+                        field_count: substs.as_closure().upvar_tys().count(),
                     }),
                 }
             }
-            AggregateKind::Generator(def_id, substs, _) => {
+            AggregateKind::Generator(_, substs, _) => {
                 // It doesn't make sense to look at a field beyond the prefix;
                 // these require a variant index, and are not initialized in
                 // aggregate rvalues.
-                match substs.as_generator().prefix_tys(def_id, tcx).nth(field_index) {
+                match substs.as_generator().prefix_tys().nth(field_index) {
                     Some(ty) => Ok(ty),
                     None => Err(FieldAccessError::OutOfRange {
-                        field_count: substs.as_generator().prefix_tys(def_id, tcx).count(),
+                        field_count: substs.as_generator().prefix_tys().count(),
                     }),
                 }
             }
@@ -2085,7 +2085,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
                     CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => {
                         let sig = match op.ty(*body, tcx).kind {
-                            ty::Closure(def_id, substs) => substs.as_closure().sig(def_id, tcx),
+                            ty::Closure(_, substs) => substs.as_closure().sig(),
                             _ => bug!(),
                         };
                         let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety);
diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
index c39694f24f7..825931cf892 100644
--- a/src/librustc_mir/borrow_check/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -108,13 +108,11 @@ impl<'tcx> DefiningTy<'tcx> {
     /// not a closure or generator, there are no upvars, and hence it
     /// will be an empty list. The order of types in this list will
     /// match up with the upvar order in the HIR, typesystem, and MIR.
-    pub fn upvar_tys(self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+    pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
         match self {
-            DefiningTy::Closure(def_id, substs) => {
-                Either::Left(substs.as_closure().upvar_tys(def_id, tcx))
-            }
-            DefiningTy::Generator(def_id, substs, _) => {
-                Either::Right(Either::Left(substs.as_generator().upvar_tys(def_id, tcx)))
+            DefiningTy::Closure(_, substs) => Either::Left(substs.as_closure().upvar_tys()),
+            DefiningTy::Generator(_, substs, _) => {
+                Either::Right(Either::Left(substs.as_generator().upvar_tys()))
             }
             DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
                 Either::Right(Either::Right(iter::empty()))
@@ -470,9 +468,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         debug!("build: local regions  = {}..{}", first_local_index, num_universals);
 
         let yield_ty = match defining_ty {
-            DefiningTy::Generator(def_id, substs, _) => {
-                Some(substs.as_generator().yield_ty(def_id, self.infcx.tcx))
-            }
+            DefiningTy::Generator(_, substs, _) => Some(substs.as_generator().yield_ty()),
             _ => None,
         };
 
@@ -580,7 +576,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         match defining_ty {
             DefiningTy::Closure(def_id, substs) => {
                 assert_eq!(self.mir_def_id, def_id);
-                let closure_sig = substs.as_closure().sig(def_id, tcx);
+                let closure_sig = substs.as_closure().sig();
                 let inputs_and_output = closure_sig.inputs_and_output();
                 let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
                 ty::Binder::fuse(closure_ty, inputs_and_output, |closure_ty, inputs_and_output| {
@@ -604,8 +600,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
             DefiningTy::Generator(def_id, substs, movability) => {
                 assert_eq!(self.mir_def_id, def_id);
-                let resume_ty = substs.as_generator().resume_ty(def_id, tcx);
-                let output = substs.as_generator().return_ty(def_id, tcx);
+                let resume_ty = substs.as_generator().resume_ty();
+                let output = substs.as_generator().return_ty();
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
                 let inputs_and_output =
                     self.infcx.tcx.intern_type_list(&[generator_ty, resume_ty, output]);
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index c1d969a4b51..eeb9d5f5a1f 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -341,8 +341,8 @@ fn build_clone_shim<'tcx>(
             let len = len.eval_usize(tcx, param_env);
             builder.array_shim(dest, src, ty, len)
         }
-        ty::Closure(def_id, substs) => {
-            builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys(def_id, tcx))
+        ty::Closure(_, substs) => {
+            builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
         }
         ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
         _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty),
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 82c5ac689b5..349cda83105 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -1236,8 +1236,8 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
             ty::Generator(_, substs, movability) => {
                 let substs = substs.as_generator();
                 (
-                    substs.upvar_tys(def_id, tcx).collect(),
-                    substs.witness(def_id, tcx),
+                    substs.upvar_tys().collect(),
+                    substs.witness(),
                     substs.discr_ty(tcx),
                     movability == hir::Movability::Movable,
                 )
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index ecf0a8ea83c..14895ddfbe4 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -798,8 +798,8 @@ where
     fn open_drop(&mut self) -> BasicBlock {
         let ty = self.place_ty(self.place);
         match ty.kind {
-            ty::Closure(def_id, substs) => {
-                let tys: Vec<_> = substs.as_closure().upvar_tys(def_id, self.tcx()).collect();
+            ty::Closure(_, substs) => {
+                let tys: Vec<_> = substs.as_closure().upvar_tys().collect();
                 self.open_drop_for_tuple(&tys)
             }
             // Note that `elaborate_drops` only drops the upvars of a generator,
@@ -808,8 +808,8 @@ where
             // This should only happen for the self argument on the resume function.
             // It effetively only contains upvars until the generator transformation runs.
             // See librustc_body/transform/generator.rs for more details.
-            ty::Generator(def_id, substs, _) => {
-                let tys: Vec<_> = substs.as_generator().upvar_tys(def_id, self.tcx()).collect();
+            ty::Generator(_, substs, _) => {
+                let tys: Vec<_> = substs.as_generator().upvar_tys().collect();
                 self.open_drop_for_tuple(&tys)
             }
             ty::Tuple(..) => {
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index d6665032931..d5daf465bb7 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -140,9 +140,7 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
 
             let (yield_ty, return_ty) = if body.generator_kind.is_some() {
                 let gen_sig = match ty.kind {
-                    ty::Generator(gen_def_id, gen_substs, ..) => {
-                        gen_substs.as_generator().sig(gen_def_id, tcx)
-                    }
+                    ty::Generator(_, gen_substs, ..) => gen_substs.as_generator().sig(),
                     _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty),
                 };
                 (Some(gen_sig.yield_ty), gen_sig.return_ty)
@@ -849,12 +847,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 closure_env_projs.push(ProjectionElem::Deref);
                 closure_ty = ty;
             }
-            let (def_id, upvar_substs) = match closure_ty.kind {
-                ty::Closure(def_id, substs) => (def_id, ty::UpvarSubsts::Closure(substs)),
-                ty::Generator(def_id, substs, _) => (def_id, ty::UpvarSubsts::Generator(substs)),
+            let upvar_substs = match closure_ty.kind {
+                ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
+                ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
                 _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty),
             };
-            let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
+            let upvar_tys = upvar_substs.upvar_tys();
             let upvars_with_tys = upvars.iter().zip(upvar_tys);
             self.upvar_mutbls = upvars_with_tys
                 .enumerate()
diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs
index 02b596863ab..148836e35c7 100644
--- a/src/librustc_mir_build/hair/cx/expr.rs
+++ b/src/librustc_mir_build/hair/cx/expr.rs
@@ -387,7 +387,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                 .upvars(def_id)
                 .iter()
                 .flat_map(|upvars| upvars.iter())
-                .zip(substs.upvar_tys(def_id, cx.tcx))
+                .zip(substs.upvar_tys())
                 .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty))
                 .collect();
             ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
@@ -830,7 +830,7 @@ fn convert_var<'tcx>(
             let region = cx.tcx.mk_region(region);
 
             let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind {
-                match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() {
+                match cx.infcx.closure_kind(closure_substs).unwrap() {
                     ty::ClosureKind::Fn => {
                         let ref_closure_ty = cx.tcx.mk_ref(
                             region,
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index 30603fde7ed..9cd97c34f3b 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -423,7 +423,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
             for required_region in required_region_bounds {
                 concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-                    tcx: self.tcx,
                     op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
                 });
             }
@@ -504,7 +503,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             }
         }
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-            tcx: self.tcx,
             op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
         });
     }
@@ -541,7 +539,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         );
 
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-            tcx: self.tcx,
             op: |r| {
                 self.member_constraint(
                     opaque_type_def_id,
@@ -682,15 +679,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 //
 // We ignore any type parameters because impl trait values are assumed to
 // capture all the in-scope type parameters.
-struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
-where
-    OP: FnMut(ty::Region<'tcx>),
-{
-    tcx: TyCtxt<'tcx>,
+struct ConstrainOpaqueTypeRegionVisitor<OP> {
     op: OP,
 }
 
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
@@ -717,27 +710,27 @@ where
         }
 
         match ty.kind {
-            ty::Closure(def_id, ref substs) => {
+            ty::Closure(_, ref substs) => {
                 // Skip lifetime parameters of the enclosing item(s)
 
-                for upvar_ty in substs.as_closure().upvar_tys(def_id, self.tcx) {
+                for upvar_ty in substs.as_closure().upvar_tys() {
                     upvar_ty.visit_with(self);
                 }
 
-                substs.as_closure().sig_as_fn_ptr_ty(def_id, self.tcx).visit_with(self);
+                substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
             }
 
-            ty::Generator(def_id, ref substs, _) => {
+            ty::Generator(_, ref substs, _) => {
                 // Skip lifetime parameters of the enclosing item(s)
                 // Also skip the witness type, because that has no free regions.
 
-                for upvar_ty in substs.as_generator().upvar_tys(def_id, self.tcx) {
+                for upvar_ty in substs.as_generator().upvar_tys() {
                     upvar_ty.visit_with(self);
                 }
 
-                substs.as_generator().return_ty(def_id, self.tcx).visit_with(self);
-                substs.as_generator().yield_ty(def_id, self.tcx).visit_with(self);
-                substs.as_generator().resume_ty(def_id, self.tcx).visit_with(self);
+                substs.as_generator().return_ty().visit_with(self);
+                substs.as_generator().yield_ty().visit_with(self);
+                substs.as_generator().resume_ty().visit_with(self);
             }
             _ => {
                 ty.super_visit_with(self);
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index d001ced3e7e..b9ee991aa02 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -481,7 +481,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
 
                     ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-                        let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
+                        let found_kind = self.closure_kind(closure_substs).unwrap();
                         let closure_span = self
                             .tcx
                             .sess
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index fdb5def1930..22b8d058396 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -367,9 +367,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     ) {
         let self_ty = trait_ref.self_ty();
         let (def_id, output_ty, callable) = match self_ty.kind {
-            ty::Closure(def_id, substs) => {
-                (def_id, substs.as_closure().sig(def_id, self.tcx).output(), "closure")
-            }
+            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
             ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"),
             _ => return,
         };
diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs
index 260363a5d1f..865a4ba866e 100644
--- a/src/librustc_trait_selection/traits/fulfill.rs
+++ b/src/librustc_trait_selection/traits/fulfill.rs
@@ -445,8 +445,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                 }
             }
 
-            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-                match self.selcx.infcx().closure_kind(closure_def_id, closure_substs) {
+            ty::Predicate::ClosureKind(_, closure_substs, kind) => {
+                match self.selcx.infcx().closure_kind(closure_substs) {
                     Some(closure_kind) => {
                         if closure_kind.extends(kind) {
                             ProcessResult::Changed(vec![])
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 6b14f6959bf..26aaf12d359 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -1237,7 +1237,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
-    let gen_sig = vtable.substs.as_generator().poly_sig(vtable.generator_def_id, selcx.tcx());
+    let gen_sig = vtable.substs.as_generator().poly_sig();
     let Normalized { value: gen_sig, obligations } = normalize_with_depth(
         selcx,
         obligation.param_env,
@@ -1310,8 +1310,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
-    let tcx = selcx.tcx();
-    let closure_sig = vtable.substs.as_closure().sig(vtable.closure_def_id, tcx);
+    let closure_sig = vtable.substs.as_closure().sig();
     let Normalized { value: closure_sig, obligations } = normalize_with_depth(
         selcx,
         obligation.param_env,
diff --git a/src/librustc_trait_selection/traits/query/dropck_outlives.rs b/src/librustc_trait_selection/traits/query/dropck_outlives.rs
index 40a21b5a6ed..03c6cf35e88 100644
--- a/src/librustc_trait_selection/traits/query/dropck_outlives.rs
+++ b/src/librustc_trait_selection/traits/query/dropck_outlives.rs
@@ -109,8 +109,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_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs
index 080eb8b3f3a..2d6fabea6ec 100644
--- a/src/librustc_trait_selection/traits/select.rs
+++ b/src/librustc_trait_selection/traits/select.rs
@@ -478,8 +478,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-                match self.infcx.closure_kind(closure_def_id, closure_substs) {
+            ty::Predicate::ClosureKind(_, closure_substs, kind) => {
+                match self.infcx.closure_kind(closure_substs) {
                     Some(closure_kind) => {
                         if closure_kind.extends(kind) {
                             Ok(EvaluatedToOk)
@@ -1600,9 +1600,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // touch bound regions, they just capture the in-scope
         // type/region parameters
         match obligation.self_ty().skip_binder().kind {
-            ty::Closure(closure_def_id, closure_substs) => {
+            ty::Closure(_, closure_substs) => {
                 debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation);
-                match self.infcx.closure_kind(closure_def_id, closure_substs) {
+                match self.infcx.closure_kind(closure_substs) {
                     Some(closure_kind) => {
                         debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
                         if closure_kind.extends(kind) {
@@ -2234,9 +2234,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect()))
             }
 
-            ty::Closure(def_id, substs) => {
+            ty::Closure(_, substs) => {
                 // (*) binder moved here
-                Where(ty::Binder::bind(substs.as_closure().upvar_tys(def_id, self.tcx()).collect()))
+                Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
             }
 
             ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
@@ -2313,17 +2313,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 tys.iter().map(|k| k.expect_ty()).collect()
             }
 
-            ty::Closure(def_id, ref substs) => {
-                substs.as_closure().upvar_tys(def_id, self.tcx()).collect()
-            }
+            ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(),
 
-            ty::Generator(def_id, ref substs, _) => {
-                let witness = substs.as_generator().witness(def_id, self.tcx());
-                substs
-                    .as_generator()
-                    .upvar_tys(def_id, self.tcx())
-                    .chain(iter::once(witness))
-                    .collect()
+            ty::Generator(_, ref substs, _) => {
+                let witness = substs.as_generator().witness();
+                substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
             }
 
             ty::GeneratorWitness(types) => {
@@ -2811,7 +2805,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs);
 
-        let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs);
+        let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs);
         let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
             self,
             obligation.param_env,
@@ -2856,7 +2850,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => bug!("closure candidate for non-closure {:?}", obligation),
         };
 
-        let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs);
+        let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
         let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
             self,
             obligation.param_env,
@@ -3338,14 +3332,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn closure_trait_ref_unnormalized(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        closure_def_id: DefId,
         substs: SubstsRef<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
-        debug!(
-            "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})",
-            obligation, closure_def_id, substs,
-        );
-        let closure_sig = substs.as_closure().sig(closure_def_id, self.tcx());
+        debug!("closure_trait_ref_unnormalized(obligation={:?}, substs={:?})", obligation, substs);
+        let closure_sig = substs.as_closure().sig();
 
         debug!("closure_trait_ref_unnormalized: closure_sig = {:?}", closure_sig);
 
@@ -3367,10 +3357,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn generator_trait_ref_unnormalized(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        closure_def_id: DefId,
         substs: SubstsRef<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
-        let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx());
+        let gen_sig = substs.as_generator().poly_sig();
 
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an generator type and hence is
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 5f40c1cefca..ac2da006df3 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -474,7 +474,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // generators don't take arguments.
                 }
 
-                ty::Closure(def_id, substs) => {
+                ty::Closure(_, substs) => {
                     // Only check the upvar types for WF, not the rest
                     // of the types within. This is needed because we
                     // capture the signature and it may not be WF
@@ -505,7 +505,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // anyway, except via auto trait matching (which
                     // only inspects the upvar types).
                     subtys.skip_current_subtree(); // subtree handled by compute_projection
-                    for upvar_ty in substs.as_closure().upvar_tys(def_id, self.infcx.tcx) {
+                    for upvar_ty in substs.as_closure().upvar_tys() {
                         self.compute(upvar_ty);
                     }
                 }
diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs
index b13a7a3acb1..7068723f534 100644
--- a/src/librustc_traits/dropck_outlives.rs
+++ b/src/librustc_traits/dropck_outlives.rs
@@ -207,13 +207,13 @@ fn dtorck_constraint_for_ty<'tcx>(
             }
         }
 
-        ty::Closure(def_id, substs) => {
-            for ty in substs.as_closure().upvar_tys(def_id, tcx) {
+        ty::Closure(_, substs) => {
+            for ty in substs.as_closure().upvar_tys() {
                 dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
             }
         }
 
-        ty::Generator(def_id, substs, _movability) => {
+        ty::Generator(_, substs, _movability) => {
             // rust-lang/rust#49918: types can be constructed, stored
             // in the interior, and sit idle when generator yields
             // (and is subsequently dropped).
@@ -240,10 +240,10 @@ fn dtorck_constraint_for_ty<'tcx>(
             constraints.outlives.extend(
                 substs
                     .as_generator()
-                    .upvar_tys(def_id, tcx)
+                    .upvar_tys()
                     .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }),
             );
-            constraints.outlives.push(substs.as_generator().resume_ty(def_id, tcx).into());
+            constraints.outlives.push(substs.as_generator().resume_ty().into());
         }
 
         ty::Adt(def, substs) => {
diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs
index 3b72da23baf..37af8168f87 100644
--- a/src/librustc_ty/needs_drop.rs
+++ b/src/librustc_ty/needs_drop.rs
@@ -93,8 +93,8 @@ where
                 match component.kind {
                     _ if component.is_copy_modulo_regions(tcx, self.param_env, DUMMY_SP) => (),
 
-                    ty::Closure(def_id, substs) => {
-                        for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) {
+                    ty::Closure(_, substs) => {
+                        for upvar_ty in substs.as_closure().upvar_tys() {
                             queue_type(self, upvar_ty);
                         }
                     }
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 056fe912d9e..ec796043d3a 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -104,8 +104,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Check whether this is a call to a closure where we
                 // haven't yet decided on whether the closure is fn vs
                 // fnmut vs fnonce. If so, we have to defer further processing.
-                if self.closure_kind(def_id, substs).is_none() {
-                    let closure_sig = substs.as_closure().sig(def_id, self.tcx);
+                if self.closure_kind(substs).is_none() {
+                    let closure_sig = substs.as_closure().sig();
                     let closure_sig = self
                         .replace_bound_vars_with_fresh_vars(
                             call_expr.span,
@@ -122,7 +122,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             adjusted_ty,
                             adjustments,
                             fn_sig: closure_sig,
-                            closure_def_id: def_id,
                             closure_substs: substs,
                         },
                     );
@@ -459,7 +458,6 @@ pub struct DeferredCallResolution<'tcx> {
     adjusted_ty: Ty<'tcx>,
     adjustments: Vec<Adjustment<'tcx>>,
     fn_sig: ty::FnSig<'tcx>,
-    closure_def_id: DefId,
     closure_substs: SubstsRef<'tcx>,
 }
 
@@ -469,7 +467,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
 
         // we should not be invoked until the closure kind has been
         // determined by upvar inference
-        assert!(fcx.closure_kind(self.closure_def_id, self.closure_substs).is_some());
+        assert!(fcx.closure_kind(self.closure_substs).is_some());
 
         // We may now know enough to figure out fn vs fnmut etc.
         match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) {
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index d8f5a83c50b..a277220b1a2 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -77,45 +77,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let generator_types =
             check_fn(self, self.param_env, liberated_sig, decl, expr.hir_id, body, gen).1;
 
-        // Create type variables (for now) to represent the transformed
-        // types of upvars. These will be unified during the upvar
-        // inference phase (`upvar.rs`).
         let base_substs =
             InternalSubsts::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
+        // HACK(eddyb) this hardcodes indices into substs but it should rely on
+        // `ClosureSubsts` and `GeneratorSubsts` providing constructors, instead.
+        // That would also remove the need for most of the inference variables,
+        // as they immediately unified with the actual type below, including
+        // the `InferCtxt::closure_sig` and `ClosureSubsts::sig_ty` methods.
+        let tupled_upvars_idx = base_substs.len() + if generator_types.is_some() { 4 } else { 2 };
         let substs = base_substs.extend_to(self.tcx, expr_def_id, |param, _| match param.kind {
             GenericParamDefKind::Lifetime => span_bug!(expr.span, "closure has lifetime param"),
-            GenericParamDefKind::Type { .. } => self
-                .infcx
-                .next_ty_var(TypeVariableOrigin {
+            GenericParamDefKind::Type { .. } => if param.index as usize == tupled_upvars_idx {
+                self.tcx.mk_tup(self.tcx.upvars(expr_def_id).iter().flat_map(|upvars| {
+                    upvars.iter().map(|(&var_hir_id, _)| {
+                        // Create type variables (for now) to represent the transformed
+                        // types of upvars. These will be unified during the upvar
+                        // inference phase (`upvar.rs`).
+                        self.infcx.next_ty_var(TypeVariableOrigin {
+                            // FIXME(eddyb) distinguish upvar inference variables from the rest.
+                            kind: TypeVariableOriginKind::ClosureSynthetic,
+                            span: self.tcx.hir().span(var_hir_id),
+                        })
+                    })
+                }))
+            } else {
+                // Create type variables (for now) to represent the various
+                // pieces of information kept in `{Closure,Generic}Substs`.
+                // They will either be unified below, or later during the upvar
+                // inference phase (`upvar.rs`)
+                self.infcx.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::ClosureSynthetic,
                     span: expr.span,
                 })
-                .into(),
+            }
+            .into(),
             GenericParamDefKind::Const => span_bug!(expr.span, "closure has const param"),
         });
         if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
         {
             let generator_substs = substs.as_generator();
-            self.demand_eqtype(
-                expr.span,
-                resume_ty,
-                generator_substs.resume_ty(expr_def_id, self.tcx),
-            );
-            self.demand_eqtype(
-                expr.span,
-                yield_ty,
-                generator_substs.yield_ty(expr_def_id, self.tcx),
-            );
-            self.demand_eqtype(
-                expr.span,
-                liberated_sig.output(),
-                generator_substs.return_ty(expr_def_id, self.tcx),
-            );
-            self.demand_eqtype(
-                expr.span,
-                interior,
-                generator_substs.witness(expr_def_id, self.tcx),
-            );
+            self.demand_eqtype(expr.span, resume_ty, generator_substs.resume_ty());
+            self.demand_eqtype(expr.span, yield_ty, generator_substs.yield_ty());
+            self.demand_eqtype(expr.span, liberated_sig.output(), generator_substs.return_ty());
+            self.demand_eqtype(expr.span, interior, generator_substs.witness());
 
             // HACK(eddyb) this forces the types equated above into `substs` but
             // it should rely on `GeneratorSubsts` providing a constructor, instead.
@@ -142,18 +146,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
 
         let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig);
-        self.demand_eqtype(
-            expr.span,
-            sig_fn_ptr_ty,
-            substs.as_closure().sig_as_fn_ptr_ty(expr_def_id, self.tcx),
-        );
+        self.demand_eqtype(expr.span, sig_fn_ptr_ty, substs.as_closure().sig_as_fn_ptr_ty());
 
         if let Some(kind) = opt_kind {
-            self.demand_eqtype(
-                expr.span,
-                kind.to_ty(self.tcx),
-                substs.as_closure().kind_ty(expr_def_id, self.tcx),
-            );
+            self.demand_eqtype(expr.span, kind.to_ty(self.tcx), substs.as_closure().kind_ty());
         }
 
         // HACK(eddyb) this forces the types equated above into `substs` but
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 70c1f5faca5..33fc18b4b6e 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -62,7 +62,6 @@ use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeAndMut};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
 use rustc_session::parse::feature_err;
@@ -236,11 +235,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 // unsafe qualifier.
                 self.coerce_from_fn_pointer(a, a_f, b)
             }
-            ty::Closure(def_id_a, substs_a) => {
+            ty::Closure(_, substs_a) => {
                 // Non-capturing closures are coercible to
                 // function pointers or unsafe function pointers.
                 // It cannot convert closures that require unsafe.
-                self.coerce_closure_to_fn(a, def_id_a, substs_a, b)
+                self.coerce_closure_to_fn(a, substs_a, b)
             }
             _ => {
                 // Otherwise, just use unification rules.
@@ -732,7 +731,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
     fn coerce_closure_to_fn(
         &self,
         a: Ty<'tcx>,
-        def_id_a: DefId,
         substs_a: SubstsRef<'tcx>,
         b: Ty<'tcx>,
     ) -> CoerceResult<'tcx> {
@@ -743,14 +741,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let b = self.shallow_resolve(b);
 
         match b.kind {
-            ty::FnPtr(fn_ty) if self.tcx.upvars(def_id_a).map_or(true, |v| v.is_empty()) => {
+            ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => {
                 // We coerce the closure, which has fn type
                 //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
                 // to
                 //     `fn(arg0,arg1,...) -> _`
                 // or
                 //     `unsafe fn(arg0,arg1,...) -> _`
-                let closure_sig = substs_a.as_closure().sig(def_id_a, self.tcx);
+                let closure_sig = substs_a.as_closure().sig();
                 let unsafety = fn_ty.unsafety();
                 let pointer_ty = self.tcx.coerce_closure_fn_ty(closure_sig, unsafety);
                 debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3006ecc5d58..3aa76a46f60 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4831,7 +4831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let hir = self.tcx.hir();
         let (def_id, sig) = match found.kind {
             ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig(def_id, self.tcx)),
+            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
             _ => return false,
         };
 
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 57a89614eb1..a1345895689 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -1228,8 +1228,8 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
 
         // A closure capture can't be borrowed for longer than the
         // reference to the closure.
-        if let ty::Closure(closure_def_id, substs) = ty.kind {
-            match self.infcx.closure_kind(closure_def_id, substs) {
+        if let ty::Closure(_, substs) = ty.kind {
+            match self.infcx.closure_kind(substs) {
                 Some(ty::ClosureKind::Fn) | Some(ty::ClosureKind::FnMut) => {
                     // Region of environment pointer
                     let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 1b5f151870c..ff4e2cdab78 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs {
-            self.closure_kind(closure_def_id, closure_substs).is_none().then_some(closure_substs)
+            self.closure_kind(closure_substs).is_none().then_some(closure_substs)
         } else {
             None
         };
@@ -168,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Unify the (as yet unbound) type variable in the closure
             // substs with the kind we inferred.
             let inferred_kind = delegate.current_closure_kind;
-            let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self.tcx);
+            let closure_kind_ty = closure_substs.as_closure().kind_ty();
             self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty);
 
             // If we have an origin, store it.
@@ -197,9 +197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
             closure_hir_id, substs, final_upvar_tys
         );
-        for (upvar_ty, final_upvar_ty) in
-            substs.upvar_tys(closure_def_id, self.tcx).zip(final_upvar_tys)
-        {
+        for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) {
             self.demand_suptype(span, upvar_ty, final_upvar_ty);
         }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index bb9354b8ab3..e5f4e2fa977 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1374,9 +1374,9 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
     // and we don't do that for closures.
     if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) = node {
         let dummy_args = if gen.is_some() {
-            &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>"][..]
+            &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
         } else {
-            &["<closure_kind>", "<closure_signature>"][..]
+            &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
         };
 
         params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
@@ -1390,22 +1390,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
                 synthetic: None,
             },
         }));
-
-        if let Some(upvars) = tcx.upvars(def_id) {
-            params.extend(upvars.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| {
-                ty::GenericParamDef {
-                    index: type_start + i,
-                    name: Symbol::intern("<upvar>"),
-                    def_id,
-                    pure_wrt_drop: false,
-                    kind: ty::GenericParamDefKind::Type {
-                        has_default: false,
-                        object_lifetime_default: rl::Set1::Empty,
-                        synthetic: None,
-                    },
-                }
-            }));
-        }
     }
 
     let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr
index 83dd93b853d..41965d6b355 100644
--- a/src/test/ui/issues/issue-22638.stderr
+++ b/src/test/ui/issues/issue-22638.stderr
@@ -8,7 +8,7 @@ LL | |         a.matches(f)
 LL | |     }
    | |_____^
    |
-   = note: consider adding a `#![type_length_limit="26214380"]` attribute to your crate
+   = note: consider adding a `#![type_length_limit="30408681"]` attribute to your crate
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
index b4e18c229fd..f0d169f419c 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -7,6 +7,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    = note: defining type: test::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)),
+               (),
            ]
 
 error: lifetime may not live long enough
diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr
index 533a17bdd12..e251e69997e 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr
@@ -7,6 +7,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    = note: defining type: test::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)),
+               (),
            ]
 
 note: no external requirements
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
index 60d02066e26..36257700bef 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -7,8 +7,7 @@ LL |             let mut closure1 = || p = &y;
    = note: defining type: test::{{closure}}#0::{{closure}}#0 with closure substs [
                i16,
                extern "rust-call" fn(()),
-               &'_#1r i32,
-               &'_#2r mut &'_#3r i32,
+               (&'_#1r i32, &'_#2r mut &'_#3r i32),
            ]
    = note: number of external vids: 4
    = note: where '_#1r: '_#3r
@@ -26,8 +25,7 @@ LL | |         };
    = note: defining type: test::{{closure}}#0 with closure substs [
                i16,
                extern "rust-call" fn(()),
-               &'_#1r i32,
-               &'_#2r mut &'_#3r i32,
+               (&'_#1r i32, &'_#2r mut &'_#3r i32),
            ]
    = note: number of external vids: 4
    = note: where '_#1r: '_#3r
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
index f64ccf14ac4..d1c64fac3c1 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -7,8 +7,7 @@ LL |         let mut closure = || p = &y;
    = note: defining type: test::{{closure}}#0 with closure substs [
                i16,
                extern "rust-call" fn(()),
-               &'_#1r i32,
-               &'_#2r mut &'_#3r i32,
+               (&'_#1r i32, &'_#2r mut &'_#3r i32),
            ]
    = note: number of external vids: 4
    = note: where '_#1r: '_#3r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index e1e0cdc153a..549ebb78d78 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -11,6 +11,7 @@ LL | |         },
    = note: defining type: supply::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#4r
    = note: late-bound region is '_#5r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index b6535024a4a..346b4af6caa 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -12,6 +12,7 @@ LL | |     });
    = note: defining type: supply::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: late-bound region is '_#4r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index f5723ba5da5..3b1769ed3a2 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -11,6 +11,7 @@ LL | |     })
    = note: defining type: case1::{{closure}}#0 with closure substs [
                i32,
                for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)),
+               (),
            ]
 
 error[E0521]: borrowed data escapes outside of closure
@@ -49,6 +50,7 @@ LL | |     })
    = note: defining type: case2::{{closure}}#0 with closure substs [
                i32,
                for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)),
+               (),
            ]
    = note: number of external vids: 2
    = note: where '_#1r: '_#0r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index 17d33e82ba7..b167dafff01 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -13,6 +13,7 @@ LL | |     });
    = note: defining type: supply::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#2r
    = note: late-bound region is '_#3r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 5dce8d087d6..91aacc3dff6 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -13,6 +13,7 @@ LL | |     });
    = note: defining type: supply::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: late-bound region is '_#4r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
index 5c5d510805b..ae447708621 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -12,6 +12,7 @@ LL | |     });
    = note: defining type: test::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: late-bound region is '_#4r
diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index c111e651832..256446a6e8d 100644
--- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -11,6 +11,7 @@ LL | |         },
    = note: defining type: supply::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: number of external vids: 4
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index 52df46ed345..5c156d0d1e3 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -12,6 +12,7 @@ LL | |     });
    = note: defining type: supply::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#2r
    = note: late-bound region is '_#3r
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index 0270cc40de6..46e3f2e75f4 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -12,6 +12,7 @@ LL | |     });
    = note: defining type: supply::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: late-bound region is '_#4r
diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
index b705ad9009a..ef941472894 100644
--- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -14,6 +14,7 @@ LL | |     });
    = note: defining type: supply::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((T,)),
+               (),
            ]
    = note: number of external vids: 2
    = note: where T: '_#1r
diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
index 79ed1501524..2a382030f93 100644
--- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
+++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -7,6 +7,7 @@ LL |     expect_sig(|a, b| b); // ought to return `a`
    = note: defining type: test::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32,
+               (),
            ]
 
 error: lifetime may not live long enough
diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
index 84365465eda..38e59ae3e26 100644
--- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -7,6 +7,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+               (),
            ]
    = note: number of external vids: 3
    = note: where <T as std::iter::Iterator>::Item: '_#2r
@@ -42,6 +43,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+               (),
            ]
    = note: number of external vids: 3
    = note: where <T as std::iter::Iterator>::Item: '_#2r
@@ -68,6 +70,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+               (),
            ]
    = note: number of external vids: 4
    = note: where <T as std::iter::Iterator>::Item: '_#3r
@@ -103,6 +106,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+               (),
            ]
    = note: number of external vids: 4
    = note: where <T as std::iter::Iterator>::Item: '_#3r
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index 118a849f984..e8aba9d8d4d 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -7,6 +7,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: number of external vids: 4
@@ -57,6 +58,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where T: '_#3r
@@ -106,6 +108,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
@@ -133,6 +136,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where T: '_#3r
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 59d8aa484bd..58ea527d959 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -7,6 +7,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: number of external vids: 4
@@ -48,6 +49,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
@@ -88,6 +90,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
@@ -115,6 +118,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where '_#2r: '_#3r
@@ -142,6 +146,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: number of external vids: 3
    = note: where '_#1r: '_#2r
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
index c3b924577ab..3d9a01fec10 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
@@ -7,6 +7,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: late-bound region is '_#3r
 
@@ -32,6 +33,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
 
 note: no external requirements
@@ -57,6 +59,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
 
 note: no external requirements
@@ -82,6 +85,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
 
 note: no external requirements
@@ -107,6 +111,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
 
 note: no external requirements
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index ff402f89ae8..7c82b147394 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -7,6 +7,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: late-bound region is '_#4r
    = note: number of external vids: 5
@@ -43,6 +44,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               (),
            ]
    = note: number of external vids: 5
    = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
@@ -78,6 +80,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               (),
            ]
    = note: number of external vids: 5
    = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
@@ -105,6 +108,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               (),
            ]
    = note: number of external vids: 5
    = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
@@ -132,6 +136,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               (),
            ]
    = note: number of external vids: 5
    = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
@@ -159,6 +164,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: two_regions::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: number of external vids: 4
@@ -200,6 +206,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
@@ -227,6 +234,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: number of external vids: 3
    = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index 9b08a107496..167ca740c65 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -7,6 +7,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    = note: defining type: generic::<T>::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)),
+               (),
            ]
    = note: number of external vids: 2
    = note: where T: '_#1r
@@ -31,6 +32,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    = note: defining type: generic_fail::<T>::{{closure}}#0 with closure substs [
                i16,
                for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)),
+               (),
            ]
    = note: late-bound region is '_#2r
    = note: number of external vids: 3
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
index 3cd1f435871..528da502b9d 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -7,6 +7,7 @@ LL |     with_signature(x, |y| y)
    = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>,
+               (),
            ]
    = note: number of external vids: 3
    = note: where T: '_#2r
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
index 4740ed645f1..e341ee48291 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -14,6 +14,7 @@ LL | |     })
    = note: defining type: no_region::<T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)),
+               (),
            ]
    = note: late-bound region is '_#2r
    = note: number of external vids: 3
@@ -64,6 +65,7 @@ LL | |     })
    = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: number of external vids: 3
    = note: where T: '_#2r
@@ -96,6 +98,7 @@ LL | |     })
    = note: defining type: wrong_region::<'_#1r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               (),
            ]
    = note: late-bound region is '_#3r
    = note: number of external vids: 4
@@ -141,6 +144,7 @@ LL | |     })
    = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
                i32,
                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               (),
            ]
    = note: number of external vids: 4
    = note: where T: '_#3r