about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoxane <roxane.fruytier@hotmail.com>2020-07-19 17:26:51 -0400
committerAman Arora <me@aman-arora.com>2020-10-11 03:32:35 -0400
commitdc183702da942f4a25bff99b2bb6073d1aa7c9f9 (patch)
tree838fde0482fafbe0e8dc4331051fd50683b57d55
parent25d2d09da7af7fcbb0661a3ff2cd1a7fba3be86e (diff)
downloadrust-dc183702da942f4a25bff99b2bb6073d1aa7c9f9.tar.gz
rust-dc183702da942f4a25bff99b2bb6073d1aa7c9f9.zip
Replace tuple of infer vars for upvar_tys with single infer var
This commit allows us to decide the number of captures required after
completing capture ananysis, which is required as part of implementing
RFC-2229.

Co-authored-by: Aman Arora <me@aman-arora.com>
Co-authored-by: Jenny Wills <wills.jenniferg@gmail.com>
-rw-r--r--compiler/rustc_middle/src/ty/outlives.rs18
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs46
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs8
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs40
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs6
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs24
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs17
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs23
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs8
-rw-r--r--src/test/ui/closures/closure-move-sync.stderr2
-rw-r--r--src/test/ui/generator/generator-yielding-or-returning-itself.stderr4
-rw-r--r--src/test/ui/generator/not-send-sync.stderr1
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-2.stderr3
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-3.stderr2
-rw-r--r--src/test/ui/generator/static-not-unpin.stderr4
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.stderr2
-rw-r--r--src/test/ui/interior-mutability/interior-mutability.stderr1
-rw-r--r--src/test/ui/kindck/kindck-nonsendable-1.stderr1
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr16
-rw-r--r--src/test/ui/no-send-res-ports.stderr1
23 files changed, 178 insertions, 95 deletions
diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs
index 4c20141bbe6..708c92af146 100644
--- a/compiler/rustc_middle/src/ty/outlives.rs
+++ b/compiler/rustc_middle/src/ty/outlives.rs
@@ -96,15 +96,25 @@ fn compute_components(
             }
 
             ty::Closure(_, ref substs) => {
-                for upvar_ty in substs.as_closure().upvar_tys() {
-                    compute_components(tcx, upvar_ty, out, visited);
+                if substs.as_closure().is_valid() {
+                    for upvar_ty in substs.as_closure().upvar_tys() {
+                        compute_components(tcx, upvar_ty, out, visited);
+                    }
+                } else {
+                    let tupled_ty = substs.as_closure().tupled_upvars_ty();
+                    compute_components(tcx, tupled_ty, out, visited);
                 }
             }
 
             ty::Generator(_, ref substs, _) => {
                 // Same as the closure case
-                for upvar_ty in substs.as_generator().upvar_tys() {
-                    compute_components(tcx, upvar_ty, out, visited);
+                if substs.as_generator().is_valid() {
+                    for upvar_ty in substs.as_generator().upvar_tys() {
+                        compute_components(tcx, upvar_ty, out, visited);
+                    }
+                } else {
+                    let tupled_ty = substs.as_generator().tupled_upvars_ty();
+                    compute_components(tcx, tupled_ty, out, visited);
                 }
 
                 // We ignore regions in the generator interior as we don't
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index e1f02d0f704..646042d407c 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -663,18 +663,13 @@ pub trait PrettyPrinter<'tcx>:
                     }
                 } else {
                     p!(print_def_path(did, substs));
-                    if substs.as_generator().is_valid() {
-                        // Search for the first inference variable
-                        p!(" upvar_tys=(");
-                        let mut uninferred_ty =
-                            substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer());
-                        if uninferred_ty.next().is_some() {
-                            p!(write("unavailable"));
-                        } else {
-                            self = self.comma_sep(substs.as_generator().upvar_tys())?;
-                        }
-                        p!(")");
+                    p!(" upvar_tys=(");
+                    if !substs.as_generator().is_valid() {
+                        p!("unavailable");
+                    } else {
+                        self = self.comma_sep(substs.as_generator().upvar_tys())?;
                     }
+                    p!(")");
                 }
 
                 if substs.as_generator().is_valid() {
@@ -704,24 +699,17 @@ pub trait PrettyPrinter<'tcx>:
                     }
                 } else {
                     p!(print_def_path(did, substs));
-                    if substs.as_closure().is_valid() {
-                        // Search for the first inference variable
-                        let mut uninferred_ty =
-                            substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer());
-                        if uninferred_ty.next().is_some() {
-                            // If the upvar substs contain an inference variable we haven't
-                            // finished capture analysis.
-                            p!(" closure_substs=(unavailable)");
-                        } else {
-                            p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
-                            p!(
-                                " closure_sig_as_fn_ptr_ty=",
-                                print(substs.as_closure().sig_as_fn_ptr_ty())
-                            );
-                            p!(" upvar_tys=(");
-                            self = self.comma_sep(substs.as_closure().upvar_tys())?;
-                            p!(")");
-                        }
+                    if !substs.as_closure().is_valid() {
+                        p!(" closure_substs=(unavailable)");
+                    } else {
+                        p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
+                        p!(
+                            " closure_sig_as_fn_ptr_ty=",
+                            print(substs.as_closure().sig_as_fn_ptr_ty())
+                        );
+                        p!(" upvar_tys=(");
+                        self = self.comma_sep(substs.as_closure().upvar_tys())?;
+                        p!(")");
                     }
                 }
                 p!("]");
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 1af56972ad0..870cc4eee05 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -656,6 +656,14 @@ impl<'tcx> UpvarSubsts<'tcx> {
         };
         tupled_upvars_ty.expect_ty().tuple_fields()
     }
+
+    #[inline]
+    pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+        match self {
+            UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(),
+            UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(),
+        }
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 610c6fd7e35..087f6a0deec 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -441,6 +441,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
             for required_region in required_region_bounds {
                 concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+                    infcx: self,
                     op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
                 });
             }
@@ -509,6 +510,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             }
         }
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+            infcx: self,
             op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
         });
     }
@@ -543,6 +545,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         );
 
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+            infcx: self,
             op: |r| {
                 self.member_constraint(
                     opaque_type_def_id,
@@ -683,11 +686,12 @@ 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<OP> {
+struct ConstrainOpaqueTypeRegionVisitor<'cx, 'tcx, OP> {
+    infcx: &'cx InferCtxt<'cx, 'tcx>,
     op: OP,
 }
 
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
+impl<'cx, 'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'cx, 'tcx, OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
@@ -717,24 +721,36 @@ where
             ty::Closure(_, ref substs) => {
                 // Skip lifetime parameters of the enclosing item(s)
 
-                for upvar_ty in substs.as_closure().upvar_tys() {
-                    upvar_ty.visit_with(self);
-                }
+                let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
+                    // Not yet resolved.
+                    ty.super_visit_with(self);
+                } else {
+                    for upvar_ty in substs.as_closure().upvar_tys() {
+                        upvar_ty.visit_with(self);
+                    }
 
-                substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
+                    substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
+                }
             }
 
             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() {
-                    upvar_ty.visit_with(self);
-                }
+                let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
+                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
+                    // Not yet resolved.
+                    ty.super_visit_with(self);
+                } else {
+                    for upvar_ty in substs.as_generator().upvar_tys() {
+                        upvar_ty.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);
+                    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/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 967374ffdc2..5908e73d483 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1307,6 +1307,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let mut generator = None;
         let mut outer_generator = None;
         let mut next_code = Some(&obligation.cause.code);
+
+        let mut seen_upvar_tys_infer_tuple = false;
+
         while let Some(code) = next_code {
             debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
             match code {
@@ -1327,6 +1330,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             outer_generator = Some(did);
                         }
                         ty::GeneratorWitness(..) => {}
+                        ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
+                            // By introducing a tuple of upvar types into the chain of obligations
+                            // of a generator, the first non-generator item is now the tuple itself,
+                            // we shall ignore this.
+
+                            seen_upvar_tys_infer_tuple = true;
+                        }
                         _ if generator.is_none() => {
                             trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
                             target_ty = Some(ty);
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 424b3bd67ff..8212823a6db 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -110,7 +110,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         // check if *any* of those are trivial.
         ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
         ty::Closure(_, ref substs) => {
-            substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
+            trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
         }
 
         ty::Adt(def, _) => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index a142ba58a69..efe01191e58 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1631,7 +1631,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             ty::Closure(_, substs) => {
                 // (*) binder moved here
-                Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
+                let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
+                    // Not yet resolved.
+                    Ambiguous
+                } else {
+                    Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
+                }
             }
 
             ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
@@ -1700,11 +1706,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 tys.iter().map(|k| k.expect_ty()).collect()
             }
 
-            ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(),
+            ty::Closure(_, ref substs) => {
+                let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
+                    // The inference variable will be replaced by a tuple once capture analysis
+                    // completes. If the tuple meets a bound, so do all the elements within it.
+                    vec![ty]
+                } else {
+                    substs.as_closure().upvar_tys().collect()
+                }
+            }
 
             ty::Generator(_, ref substs, _) => {
-                let witness = substs.as_generator().witness();
-                substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
+                let upvar_tys_resolved =
+                    self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
+
+                if let ty::Infer(ty::TyVar(_)) = upvar_tys_resolved.kind() {
+                    // The inference variable will be replaced by a tuple once capture analysis
+                    // completes, if the tuple meets a bound, so do all the elements within it.
+                    let witness_resolved =
+                        self.infcx.shallow_resolve(substs.as_generator().witness());
+                    vec![upvar_tys_resolved, witness_resolved]
+                } else {
+                    let witness = substs.as_generator().witness();
+                    substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
+                }
             }
 
             ty::GeneratorWitness(types) => {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d66bfd48206..496dff6c5b2 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -592,10 +592,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // anyway, except via auto trait matching (which
                     // only inspects the upvar types).
                     walker.skip_current_subtree(); // subtree handled below
-                    for upvar_ty in substs.as_closure().upvar_tys() {
-                        // FIXME(eddyb) add the type to `walker` instead of recursing.
-                        self.compute(upvar_ty.into());
-                    }
+                    // FIXME(eddyb) add the type to `walker` instead of recursing.
+                    self.compute(substs.as_closure().tupled_upvars_ty().into());
                 }
 
                 ty::FnPtr(_) => {
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 3ee391d6dc7..bbd3a7229a9 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -210,12 +210,20 @@ fn dtorck_constraint_for_ty<'tcx>(
             Ok::<_, NoSolution>(())
         })?,
 
-        ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
-            for ty in substs.as_closure().upvar_tys() {
-                dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
+        ty::Closure(_, substs) => {
+            if !substs.as_closure().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+                return Err(NoSolution);
             }
-            Ok::<_, NoSolution>(())
-        })?,
+
+            rustc_data_structures::stack::ensure_sufficient_stack(|| {
+                for ty in substs.as_closure().upvar_tys() {
+                    dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
+                }
+                Ok::<_, NoSolution>(())
+            })?
+        }
 
         ty::Generator(_, substs, _movability) => {
             // rust-lang/rust#49918: types can be constructed, stored
@@ -241,6 +249,12 @@ fn dtorck_constraint_for_ty<'tcx>(
             // derived from lifetimes attached to the upvars and resume
             // argument, and we *do* incorporate those here.
 
+            if !substs.as_generator().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+                return Err(NoSolution);
+            }
+
             constraints.outlives.extend(
                 substs
                     .as_generator()
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 8898a545228..8bdd933644a 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -81,19 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
         );
 
-        let tupled_upvars_ty =
-            self.tcx.mk_tup(self.tcx.upvars_mentioned(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),
-                    })
-                })
-            }));
+        let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::ClosureSynthetic,
+            span: self.tcx.hir().span(expr.hir_id),
+        });
 
         if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
         {
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 4addee1a4c9..db32a736181 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -39,6 +39,7 @@ use crate::astconv::AstConv;
 use crate::check::FnCtxt;
 use rustc_errors::{struct_span_err, Applicability, 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_middle::ty::adjustment::{
@@ -221,11 +222,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 // unsafe qualifier.
                 self.coerce_from_fn_pointer(a, a_f, b)
             }
-            ty::Closure(_, substs_a) => {
+            ty::Closure(closure_def_id_a, 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, substs_a, b)
+                self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b)
             }
             _ => {
                 // Otherwise, just use unification rules.
@@ -762,6 +763,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
     fn coerce_closure_to_fn(
         &self,
         a: Ty<'tcx>,
+        closure_def_id_a: DefId,
         substs_a: SubstsRef<'tcx>,
         b: Ty<'tcx>,
     ) -> CoerceResult<'tcx> {
@@ -772,7 +774,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let b = self.shallow_resolve(b);
 
         match b.kind() {
-            ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => {
+            // At this point we haven't done capture analysis, which means
+            // that the ClosureSubsts just contains an inference variable instead
+            // of tuple of captured types.
+            //
+            // All we care here is if any variable is being captured and not the exact paths,
+            // so we check `upvars_mentioned` for root variables being captured.
+            ty::FnPtr(fn_ty)
+                if self
+                    .tcx
+                    .upvars_mentioned(closure_def_id_a.expect_local())
+                    .map_or(true, |u| u.is_empty()) =>
+            {
                 // We coerce the closure, which has fn type
                 //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
                 // to
@@ -906,8 +919,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
         let (a_sig, b_sig) = {
             let is_capturing_closure = |ty| {
-                if let &ty::Closure(_, substs) = ty {
-                    substs.as_closure().upvar_tys().next().is_some()
+                if let &ty::Closure(closure_def_id, _substs) = ty {
+                    self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some()
                 } else {
                     false
                 }
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 2c3be0da5dd..1e97bd65a79 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -202,9 +202,11 @@ 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().zip(final_upvar_tys) {
-            self.demand_suptype(span, upvar_ty, final_upvar_ty);
-        }
+
+        // Build a tuple (U0..Un) of the final upvar types U0..Un
+        // and unify the upvar tupe type in the closure with it:
+        let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
+        self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
 
         // If we are also inferred the closure kind here,
         // process any deferred resolutions.
diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr
index da5e25c0d18..285b6543833 100644
--- a/src/test/ui/closures/closure-move-sync.stderr
+++ b/src/test/ui/closures/closure-move-sync.stderr
@@ -11,6 +11,7 @@ LL |     F: Send + 'static,
    |
    = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>`
    = note: required because of the requirements on the impl of `Send` for `&std::sync::mpsc::Receiver<()>`
+   = note: required because it appears within the type `(&std::sync::mpsc::Receiver<()>,)`
    = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6]`
 
 error[E0277]: `Sender<()>` cannot be shared between threads safely
@@ -26,6 +27,7 @@ LL |     F: Send + 'static,
    |
    = help: the trait `Sync` is not implemented for `Sender<()>`
    = note: required because of the requirements on the impl of `Send` for `&Sender<()>`
+   = note: required because it appears within the type `(&Sender<()>,)`
    = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42]`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
index 16a5ab2cc86..5043a3be91d 100644
--- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
+++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]`
   --> $DIR/generator-yielding-or-returning-itself.rs:15:5
    |
 LL | pub fn want_cyclic_generator_return<T>(_: T)
@@ -14,7 +14,7 @@ LL |     want_cyclic_generator_return(|| {
            see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
            for more information
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]`
   --> $DIR/generator-yielding-or-returning-itself.rs:28:5
    |
 LL | pub fn want_cyclic_generator_yield<T>(_: T)
diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr
index 2384ed3d249..f5cfa83f500 100644
--- a/src/test/ui/generator/not-send-sync.stderr
+++ b/src/test/ui/generator/not-send-sync.stderr
@@ -9,6 +9,7 @@ LL |     assert_send(|| {
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: required because of the requirements on the impl of `Send` for `&Cell<i32>`
+   = note: required because it appears within the type `(&Cell<i32>,)`
    = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 _]`
 
 error: generator cannot be shared between threads safely
diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr
index cc45d5631cb..f363ed6a3b9 100644
--- a/src/test/ui/generator/print/generator-print-verbose-2.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr
@@ -9,7 +9,8 @@ LL |     assert_send(|| {
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell<i32>`
-   = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#16t]`
+   = note: required because it appears within the type `(&'_#3r Cell<i32>,)`
+   = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#17t]`
 
 error: generator cannot be shared between threads safely
   --> $DIR/generator-print-verbose-2.rs:12:5
diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr
index 0ce108dfd62..d15646259b2 100644
--- a/src/test/ui/generator/print/generator-print-verbose-3.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr
@@ -12,7 +12,7 @@ LL | |     };
    | |_____^ expected `()`, found generator
    |
    = note: expected unit type `()`
-              found generator `[main::{closure#0} upvar_tys=(unavailable) _#5t]`
+              found generator `[main::{closure#0} upvar_tys=(unavailable)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr
index 216b707bb16..881064d2f84 100644
--- a/src/test/ui/generator/static-not-unpin.stderr
+++ b/src/test/ui/generator/static-not-unpin.stderr
@@ -1,11 +1,11 @@
-error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned
+error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` cannot be unpinned
   --> $DIR/static-not-unpin.rs:14:18
    |
 LL | fn assert_unpin<T: Unpin>(_: T) {
    |                    ----- required by this bound in `assert_unpin`
 ...
 LL |     assert_unpin(generator);
-   |                  ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]`
+   |                  ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
index 8f6f87f78de..9e111d68a55 100644
--- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -7,7 +7,7 @@ LL |         5
    = note: expected type `std::result::Result<{integer}, _>`
               found type `{integer}`
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as Generator>::Return == i32`
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
    |
 LL | fn foo() -> impl Generator<Return = i32> {
diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr
index dd43da11664..cddfe6c6946 100644
--- a/src/test/ui/interior-mutability/interior-mutability.stderr
+++ b/src/test/ui/interior-mutability/interior-mutability.stderr
@@ -12,6 +12,7 @@ LL | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
    = help: within `Cell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
    = note: required because it appears within the type `Cell<i32>`
    = note: required because of the requirements on the impl of `UnwindSafe` for `&Cell<i32>`
+   = note: required because it appears within the type `(&Cell<i32>,)`
    = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35]`
 
 error: aborting due to previous error
diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr
index c7d67a991bf..f942088eb7e 100644
--- a/src/test/ui/kindck/kindck-nonsendable-1.stderr
+++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr
@@ -10,6 +10,7 @@ LL |     bar(move|| foo(x));
    |     `Rc<usize>` cannot be sent between threads safely
    |
    = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`, the trait `Send` is not implemented for `Rc<usize>`
+   = note: required because it appears within the type `(Rc<usize>,)`
    = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`
 
 error: aborting due to previous error
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index 63c04bcd7ba..0b1fcf58e2e 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -1,3 +1,11 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/issue-36053-2.rs:7:32
+   |
+LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
+   |                                |
+   |                                expected signature of `for<'r> fn(&'r &str) -> _`
+
 error[E0599]: no method named `count` found for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope
   --> $DIR/issue-36053-2.rs:7:55
    |
@@ -20,14 +28,6 @@ LL | pub struct Filter<I, P> {
            `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
            which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/issue-36053-2.rs:7:32
-   |
-LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
-   |                                |
-   |                                expected signature of `for<'r> fn(&'r &str) -> _`
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0599, E0631.
diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr
index ef7fb4ad7b2..8842b181586 100644
--- a/src/test/ui/no-send-res-ports.stderr
+++ b/src/test/ui/no-send-res-ports.stderr
@@ -19,6 +19,7 @@ LL |       F: Send + 'static,
    = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`, the trait `Send` is not implemented for `Rc<()>`
    = note: required because it appears within the type `Port<()>`
    = note: required because it appears within the type `Foo`
+   = note: required because it appears within the type `(Foo,)`
    = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`
 
 error: aborting due to previous error