about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-12-30 11:34:24 +0000
committerbors <bors@rust-lang.org>2021-12-30 11:34:24 +0000
commitf8d4ee7c7adcea52dfc62328309f5ef7df000266 (patch)
treeeb49cc73ccf46fca54c4860a86be5e241eebe9f9
parent65d8785f0a85d233e00fc84445f1aab451ec9f4f (diff)
parentb15cb29a4a0625afeac07fbf3ab02b63c51ad317 (diff)
downloadrust-f8d4ee7c7adcea52dfc62328309f5ef7df000266.tar.gz
rust-f8d4ee7c7adcea52dfc62328309f5ef7df000266.zip
Auto merge of #89336 - Aaron1011:variance-struct-diag, r=cjgillot
Refactor variance diagnostics to work with more types

Instead of special-casing mutable pointers/references, we
now support general generic types (currently, we handle
`ty::Ref`, `ty::RawPtr`, and `ty::Adt`)

When a `ty::Adt` is involved, we show an additional note
explaining which of the type's generic parameters is
invariant (e.g. the `T` in `Cell<T>`). Currently, we don't
explain *why* a particular generic parameter ends up becoming
invariant. In the general case, this could require printing
a long 'backtrace' of types, so doing this would be
more suitable for a follow-up PR.

We still only handle the case where our variance switches
to `ty::Invariant`.
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs44
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs37
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs30
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr6
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr6
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr4
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-4.stderr28
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr6
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr4
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr4
-rw-r--r--src/test/ui/nll/where_clauses_in_structs.stderr3
-rw-r--r--src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr3
-rw-r--r--src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr3
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-infer-not-param.nll.stderr6
-rw-r--r--src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr3
-rw-r--r--src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr4
-rw-r--r--src/test/ui/variance/variance-btree-invariant-types.nll.stderr64
-rw-r--r--src/test/ui/variance/variance-cell-is-invariant.nll.stderr3
-rw-r--r--src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr6
25 files changed, 247 insertions, 40 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 11cdbe84acc..df23eaf24bc 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -6,7 +6,7 @@ use rustc_infer::infer::{
     error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
 };
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
@@ -334,13 +334,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
         match variance_info {
             ty::VarianceDiagInfo::None => {}
-            ty::VarianceDiagInfo::Mut { kind, ty } => {
-                let kind_name = match kind {
-                    ty::VarianceDiagMutKind::Ref => "reference",
-                    ty::VarianceDiagMutKind::RawPtr => "pointer",
+            ty::VarianceDiagInfo::Invariant { ty, param_index } => {
+                let (desc, note) = match ty.kind() {
+                    ty::RawPtr(ty_mut) => {
+                        assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut);
+                        (
+                            format!("a mutable pointer to {}", ty_mut.ty),
+                            "mutable pointers are invariant over their type parameter".to_string(),
+                        )
+                    }
+                    ty::Ref(_, inner_ty, mutbl) => {
+                        assert_eq!(*mutbl, rustc_hir::Mutability::Mut);
+                        (
+                            format!("a mutable reference to {}", inner_ty),
+                            "mutable references are invariant over their type parameter"
+                                .to_string(),
+                        )
+                    }
+                    ty::Adt(adt, substs) => {
+                        let generic_arg = substs[param_index as usize];
+                        let identity_substs =
+                            InternalSubsts::identity_for_item(self.infcx.tcx, adt.did);
+                        let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs);
+                        let base_generic_arg = identity_substs[param_index as usize];
+                        let adt_desc = adt.descr();
+
+                        let desc = format!(
+                            "the type {ty}, which makes the generic argument {generic_arg} invariant"
+                        );
+                        let note = format!(
+                            "the {adt_desc} {base_ty} is invariant over the parameter {base_generic_arg}"
+                        );
+                        (desc, note)
+                    }
+                    _ => panic!("Unexpected type {:?}", ty),
                 };
-                diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",));
-                diag.note(&format!("mutable {kind_name}s are invariant over their type parameter"));
+                diag.note(&format!("requirement occurs because of {desc}",));
+                diag.note(&note);
                 diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
             }
         }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 5e48fbf253d..da71edbd2d9 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -572,8 +572,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
             // (e.g., #41849).
             relate::relate_substs(self, None, a_subst, b_subst)
         } else {
-            let opt_variances = self.tcx().variances_of(item_def_id);
-            relate::relate_substs(self, Some(&opt_variances), a_subst, b_subst)
+            let tcx = self.tcx();
+            let opt_variances = tcx.variances_of(item_def_id);
+            relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst)
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 37d99766da9..78ccfbd5e8c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -77,7 +77,7 @@ pub use self::sty::{
     GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
     ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
     PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
-    UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+    UpvarSubsts, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 905a5c47d2b..63ed318cadb 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -6,7 +6,7 @@
 
 use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
 use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
+use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
@@ -59,8 +59,9 @@ pub trait TypeRelation<'tcx>: Sized {
             item_def_id, a_subst, b_subst
         );
 
-        let opt_variances = self.tcx().variances_of(item_def_id);
-        relate_substs(self, Some(opt_variances), a_subst, b_subst)
+        let tcx = self.tcx();
+        let opt_variances = tcx.variances_of(item_def_id);
+        relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst)
     }
 
     /// Switch variance for the purpose of relating `a` and `b`.
@@ -116,7 +117,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
     a: ty::TypeAndMut<'tcx>,
     b: ty::TypeAndMut<'tcx>,
-    kind: ty::VarianceDiagMutKind,
+    base_ty: Ty<'tcx>,
 ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
     debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
     if a.mutbl != b.mutbl {
@@ -125,7 +126,9 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
         let mutbl = a.mutbl;
         let (variance, info) = match mutbl {
             ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
-            ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }),
+            ast::Mutability::Mut => {
+                (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 })
+            }
         };
         let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
         Ok(ty::TypeAndMut { ty, mutbl })
@@ -134,15 +137,29 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
 
 pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
-    variances: Option<&[ty::Variance]>,
+    variances: Option<(DefId, &[ty::Variance])>,
     a_subst: SubstsRef<'tcx>,
     b_subst: SubstsRef<'tcx>,
 ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
     let tcx = relation.tcx();
+    let mut cached_ty = None;
 
     let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
-        let variance = variances.map_or(ty::Invariant, |v| v[i]);
-        relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b)
+        let (variance, variance_info) = match variances {
+            Some((ty_def_id, variances)) => {
+                let variance = variances[i];
+                let variance_info = if variance == ty::Invariant {
+                    let ty =
+                        cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+                    ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
+                } else {
+                    ty::VarianceDiagInfo::default()
+                };
+                (variance, variance_info)
+            }
+            None => (ty::Invariant, ty::VarianceDiagInfo::default()),
+        };
+        relation.relate_with_variance(variance, variance_info, a, b)
     });
 
     tcx.mk_substs(params)
@@ -436,7 +453,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         }
 
         (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
-            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
             Ok(tcx.mk_ptr(mt))
         }
 
@@ -449,7 +466,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             )?;
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
-            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
             Ok(tcx.mk_ref(r, mt))
         }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 8706661b250..c24a1d8eb52 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2282,36 +2282,26 @@ pub enum VarianceDiagInfo<'tcx> {
     /// We will not add any additional information to error messages.
     #[default]
     None,
-    /// We switched our variance because a type occurs inside
-    /// the generic argument of a mutable reference or pointer
-    /// (`*mut T` or `&mut T`). In either case, our variance
-    /// will always be `Invariant`.
-    Mut {
-        /// Tracks whether we had a mutable pointer or reference,
-        /// for better error messages
-        kind: VarianceDiagMutKind,
-        /// The type parameter of the mutable pointer/reference
-        /// (the `T` in `&mut T` or `*mut T`).
+    /// We switched our variance because a generic argument occurs inside
+    /// the invariant generic argument of another type.
+    Invariant {
+        /// The generic type containing the generic parameter
+        /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`)
         ty: Ty<'tcx>,
+        /// The index of the generic parameter being used
+        /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`)
+        param_index: u32,
     },
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum VarianceDiagMutKind {
-    /// A mutable raw pointer (`*mut T`)
-    RawPtr,
-    /// A mutable reference (`&mut T`)
-    Ref,
-}
-
 impl<'tcx> VarianceDiagInfo<'tcx> {
     /// Mirrors `Variance::xform` - used to 'combine' the existing
     /// and new `VarianceDiagInfo`s when our variance changes.
     pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
-        // For now, just use the first `VarianceDiagInfo::Mut` that we see
+        // For now, just use the first `VarianceDiagInfo::Invariant` that we see
         match self {
             VarianceDiagInfo::None => other,
-            VarianceDiagInfo::Mut { .. } => self,
+            VarianceDiagInfo::Invariant { .. } => self,
         }
     }
 }
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
index 4fc336122fa..01f800811ab 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
@@ -10,6 +10,9 @@ LL |     (a, b)
    |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant
+   = note: the struct Type<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/project-fn-ret-invariant.rs:56:5
@@ -23,6 +26,9 @@ LL |     (a, b)
    |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant
+   = note: the struct Type<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'a` and `'b` must be the same: replace one with the other
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
index 44850df7b2f..e925a424c37 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
@@ -10,6 +10,9 @@ LL |     let a = bar(f, x);
    |             ^^^^^^^^^ argument requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant
+   = note: the struct Type<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/project-fn-ret-invariant.rs:40:13
@@ -23,6 +26,9 @@ LL |     let b = bar(f, y);
    |             ^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant
+   = note: the struct Type<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'a` and `'b` must be the same: replace one with the other
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
index c417cdd543e..0457f142e19 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
@@ -6,6 +6,10 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
 ...
 LL |     bar(foo, x)
    |     ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant
+   = note: the struct Type<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr
index cf73403bbae..4b03fe15494 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr
@@ -7,6 +7,10 @@ LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f
    |                                     lifetime `'f` defined here
 LL |     ap
    |     ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f`
+   |
+   = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
+   = note: the struct VaListImpl<'f> is invariant over the parameter 'f
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:8:5
@@ -17,6 +21,10 @@ LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f
    |                                     lifetime `'f` defined here
 LL |     ap
    |     ^^ returning this value requires that `'1` must outlive `'f`
+   |
+   = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
+   = note: the struct VaListImpl<'f> is invariant over the parameter 'f
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:14:5
@@ -25,6 +33,10 @@ LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'stati
    |                                               -- has type `VaListImpl<'1>`
 LL |     ap
    |     ^^ returning this value requires that `'1` must outlive `'static`
+   |
+   = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
+   = note: the struct VaListImpl<'f> is invariant over the parameter 'f
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:18:31
@@ -44,6 +56,10 @@ LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     *ap0 = ap1;
    |     ^^^^ assignment requires that `'1` must outlive `'2`
+   |
+   = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
+   = note: the struct VaListImpl<'f> is invariant over the parameter 'f
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:22:5
@@ -54,6 +70,10 @@ LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     *ap0 = ap1;
    |     ^^^^ assignment requires that `'2` must outlive `'1`
+   |
+   = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
+   = note: the struct VaListImpl<'f> is invariant over the parameter 'f
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:28:5
@@ -106,6 +126,10 @@ LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     *ap0 = ap1.clone();
    |            ^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+   = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
+   = note: the struct VaListImpl<'f> is invariant over the parameter 'f
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:35:12
@@ -116,6 +140,10 @@ LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     *ap0 = ap1.clone();
    |            ^^^^^^^^^^^ argument requires that `'2` must outlive `'1`
+   |
+   = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
+   = note: the struct VaListImpl<'f> is invariant over the parameter 'f
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
index e25acebf7f6..b4c54d52e5c 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
@@ -13,6 +13,9 @@ LL | | fn(Inv<'y>)) }
    | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
+   = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant
+   = note: the struct Inv<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
    = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: lifetime may not live long enough
@@ -30,6 +33,9 @@ LL | | fn(Inv<'y>)) }
    | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
+   = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant
+   = note: the struct Inv<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
    = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
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 d77793291c5..cf563072dff 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
@@ -51,6 +51,10 @@ LL | |     });
    | |      |
    | |______`cell_a` escapes the function body here
    |        argument requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Cell<&'_#10r u32>, which makes the generic argument &'_#10r u32 invariant
+   = note: the struct Cell<T> is invariant over the parameter T
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
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 cc67270ad20..453f6801d7e 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
@@ -51,6 +51,10 @@ LL | |     });
    | |      |
    | |______`cell_a` escapes the function body here
    |        argument requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Cell<&'_#11r u32>, which makes the generic argument &'_#11r u32 invariant
+   = note: the struct Cell<T> is invariant over the parameter T
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/where_clauses_in_structs.stderr b/src/test/ui/nll/where_clauses_in_structs.stderr
index 8499b00f6f5..952667d518d 100644
--- a/src/test/ui/nll/where_clauses_in_structs.stderr
+++ b/src/test/ui/nll/where_clauses_in_structs.stderr
@@ -9,6 +9,9 @@ LL |     Foo { x, y };
    |           ^ this usage requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of the type Cell<&u32>, which makes the generic argument &u32 invariant
+   = note: the struct Cell<T> is invariant over the parameter T
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
index e220cbf5559..376534bf573 100644
--- a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
+++ b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
@@ -11,6 +11,10 @@ LL |         x.unwrap()
    |         |
    |         `x` escapes the function body here
    |         argument requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant
+   = note: the struct Invariant<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr
index 47796e50a88..32f3080ea37 100644
--- a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr
+++ b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr
@@ -10,6 +10,9 @@ LL |     a.bigger_region(b)
    |     ^^^^^^^^^^^^^^^^^^ argument requires that `'y` must outlive `'x`
    |
    = help: consider adding the following bound: `'y: 'x`
+   = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant
+   = note: the struct Inv<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
index 83d6e13dc0a..62032bcb609 100644
--- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
+++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
@@ -15,6 +15,9 @@ LL |     f.method(b);
    |     argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant
+   = note: the struct Inv<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr
index 0c1e3989b23..fede5f2d779 100644
--- a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr
@@ -5,6 +5,10 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
    |                       -- lifetime `'r` defined here
 LL |     b_isize
    |     ^^^^^^^ returning this value requires that `'r` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant
+   = note: the struct Invariant<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr
index 0edeb272399..8f5f3667453 100644
--- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr
@@ -5,6 +5,10 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
    |                       -- lifetime `'r` defined here
 LL |     b_isize
    |     ^^^^^^^ returning this value requires that `'r` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant
+   = note: the struct Invariant<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr
index 724dd7e3f6d..8079fb0ef0d 100644
--- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr
@@ -5,6 +5,10 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
    |                       -- lifetime `'r` defined here
 LL |     b_isize
    |     ^^^^^^^ returning this value requires that `'r` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant
+   = note: the struct Invariant<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-infer-not-param.nll.stderr b/src/test/ui/regions/regions-infer-not-param.nll.stderr
index fcc2ec31f3e..e211f9d1391 100644
--- a/src/test/ui/regions/regions-infer-not-param.nll.stderr
+++ b/src/test/ui/regions/regions-infer-not-param.nll.stderr
@@ -17,6 +17,9 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |                   lifetime `'a` defined here
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of the type Indirect2<'_>, which makes the generic argument '_ invariant
+   = note: the struct Indirect2<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/regions-infer-not-param.rs:19:63
@@ -27,6 +30,9 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |                   lifetime `'a` defined here
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of the type Indirect2<'_>, which makes the generic argument '_ invariant
+   = note: the struct Indirect2<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'b` and `'a` must be the same: replace one with the other
 
diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
index d51db99f81f..8e8ca8e47cc 100644
--- a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
+++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
@@ -10,6 +10,9 @@ LL |     let _: Invariant<'short> = c;
    |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
    |
    = help: consider adding the following bound: `'short: 'long`
+   = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant
+   = note: the struct Invariant<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
index 15853e6ca5d..f9a3d727f7a 100644
--- a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
+++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
@@ -6,6 +6,10 @@ LL | fn use_<'b>(c: Invariant<'b>) {
 ...
 LL |     let _: Invariant<'static> = c;
    |            ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static`
+   |
+   = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant
+   = note: the struct Invariant<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr
index 1f06949c033..867d9f8238a 100644
--- a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr
+++ b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr
@@ -5,6 +5,10 @@ LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &
    |                     ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:7:5
@@ -13,6 +17,10 @@ LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (
    |                     ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:10:5
@@ -21,6 +29,10 @@ LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &
    |                        ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:13:5
@@ -29,6 +41,10 @@ LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (
    |                        ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:17:5
@@ -37,6 +53,10 @@ LL | fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a
    |                      ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type RangeMut<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct RangeMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:20:5
@@ -45,6 +65,10 @@ LL | fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a
    |                      ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type RangeMut<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct RangeMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:23:5
@@ -53,6 +77,10 @@ LL | fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a
    |                         ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type RangeMut<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct RangeMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:26:5
@@ -61,6 +89,10 @@ LL | fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a
    |                         ---- lifetime `'new` defined here
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type RangeMut<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct RangeMut<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:31:5
@@ -70,6 +102,10 @@ LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>)
 LL |                          -> OccupiedEntry<'a, &'new (), ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:35:5
@@ -79,6 +115,10 @@ LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>)
 LL |                          -> OccupiedEntry<'a, (), &'new ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:39:5
@@ -88,6 +128,10 @@ LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>)
 LL |                             -> OccupiedEntry<'a, &'static (), ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:43:5
@@ -97,6 +141,10 @@ LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>)
 LL |                             -> OccupiedEntry<'a, (), &'static ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:48:5
@@ -106,6 +154,10 @@ LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>)
 LL |                          -> VacantEntry<'a, &'new (), ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:52:5
@@ -115,6 +167,10 @@ LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>)
 LL |                          -> VacantEntry<'a, (), &'new ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:56:5
@@ -124,6 +180,10 @@ LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>)
 LL |                             -> VacantEntry<'a, &'static (), ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, &(), ()>, which makes the generic argument &() invariant
+   = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-btree-invariant-types.rs:60:5
@@ -133,6 +193,10 @@ LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>)
 LL |                             -> VacantEntry<'a, (), &'static ()> {
 LL |     v
    |     ^ returning this value requires that `'new` must outlive `'static`
+   |
+   = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, (), &()>, which makes the generic argument () invariant
+   = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to 16 previous errors
 
diff --git a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
index 1fcdfc4b5bb..d6a85680141 100644
--- a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
+++ b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
@@ -10,6 +10,9 @@ LL |     let _: Foo<'long> = c;
    |            ^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
    |
    = help: consider adding the following bound: `'short: 'long`
+   = note: requirement occurs because of the type Foo<'_>, which makes the generic argument '_ invariant
+   = note: the struct Foo<'a> is invariant over the parameter 'a
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
index 385d83adaf8..6890cb115c3 100644
--- a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
+++ b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
@@ -10,6 +10,9 @@ LL |     v
    |     ^ returning this value requires that `'min` must outlive `'max`
    |
    = help: consider adding the following bound: `'min: 'max`
+   = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant
+   = note: the struct SomeStruct<T> is invariant over the parameter T
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variance-use-invariant-struct-1.rs:19:5
@@ -23,6 +26,9 @@ LL |     v
    |     ^ returning this value requires that `'min` must outlive `'max`
    |
    = help: consider adding the following bound: `'min: 'max`
+   = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant
+   = note: the struct SomeStruct<T> is invariant over the parameter T
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to 2 previous errors