]> git.lizzy.rs Git - rust.git/commitdiff
Add variance-related information to lifetime error messages
authorAaron Hill <aa1ronham@gmail.com>
Thu, 13 May 2021 13:30:14 +0000 (09:30 -0400)
committerAaron Hill <aa1ronham@gmail.com>
Sun, 6 Jun 2021 17:37:42 +0000 (12:37 -0500)
33 files changed:
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/equate.rs
compiler/rustc_infer/src/infer/glb.rs
compiler/rustc_infer/src/infer/lub.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/sub.rs
compiler/rustc_middle/src/ty/_match.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_mir/src/borrow_check/constraints/graph.rs
compiler/rustc_mir/src/borrow_check/constraints/mod.rs
compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs
compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs
compiler/rustc_mir/src/borrow_check/type_check/mod.rs
compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
compiler/rustc_mir/src/lib.rs
compiler/rustc_typeck/src/check/dropck.rs
src/test/ui/c-variadic/variadic-ffi-4.stderr
src/test/ui/match/match-ref-mut-invariance.nll.stderr
src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
src/test/ui/nll/type-check-pointer-coercions.stderr
src/test/ui/nll/type-check-pointer-comparisons.stderr
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
src/test/ui/regions/regions-trait-object-subtyping.nll.stderr

index b8ecc949588fb0658d3e79b7c416018d220773c1..c3c28d70081512550f398aacac7337d78888947d 100644 (file)
@@ -660,7 +660,12 @@ fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<
         )
     }
 
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        _info: ty::VarianceDiagInfo<'tcx>,
+    ) {
         self.obligations.push(Obligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
index 30214e94203d81d078d413709ea2365f8b8487fa..3a11b5a214490088d71ef7f4ff7cb8518b9c4d7b 100644 (file)
@@ -371,9 +371,12 @@ pub fn instantiate(
         match dir {
             EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
             SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
-            SupertypeOf => {
-                self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty)
-            }
+            SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+                ty::Contravariant,
+                ty::VarianceDiagInfo::default(),
+                a_ty,
+                b_ty,
+            ),
         }?;
 
         Ok(())
@@ -574,6 +577,7 @@ fn relate_item_substs(
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -737,7 +741,12 @@ fn consts(
                 if self.tcx().lazy_normalization() =>
             {
                 assert_eq!(promoted, None);
-                let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+                let substs = self.relate_with_variance(
+                    ty::Variance::Invariant,
+                    ty::VarianceDiagInfo::default(),
+                    substs,
+                    substs,
+                )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
@@ -831,6 +840,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -965,7 +975,12 @@ fn consts(
                 if self.tcx().lazy_normalization() =>
             {
                 assert_eq!(promoted, None);
-                let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+                let substs = self.relate_with_variance(
+                    ty::Variance::Invariant,
+                    ty::VarianceDiagInfo::default(),
+                    substs,
+                    substs,
+                )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
index 45ba50bb6349cc9d177d81f6534601508bebdf87..0c93271a1aeca716844af99337c8f8e7e9fd8bb7 100644 (file)
@@ -59,6 +59,7 @@ fn relate_item_substs(
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index 02662043dba798088284696de403c25f30476984..60f02b84aa344225f73a762884c33e783d628a03 100644 (file)
@@ -43,6 +43,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -96,7 +97,7 @@ fn binders<T>(
         // When higher-ranked types are involved, computing the LUB is
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
-        self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+        self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
         Ok(a)
     }
 }
index 4fa8f2f1a6a426c82ec5bb6f9348a54a2e23f164..a08323535c55abd6d926abb15df0246800b8d66a 100644 (file)
@@ -43,6 +43,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -96,7 +97,7 @@ fn binders<T>(
         // When higher-ranked types are involved, computing the LUB is
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
-        self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+        self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
         Ok(a)
     }
 }
index 077d2cc20a25c3fdaf7bc8f20c4325f024baf5d1..20be06adfd09e1a37c64991476ee00f4d85cedca 100644 (file)
@@ -55,6 +55,8 @@ pub struct TypeRelating<'me, 'tcx, D>
     /// - Bivariant means that it doesn't matter.
     ambient_variance: ty::Variance,
 
+    ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
+
     /// When we pass through a set of binders (e.g., when looking into
     /// a `fn` type), we push a new bound region scope onto here. This
     /// will contain the instantiated region for each region in those
@@ -78,7 +80,12 @@ pub trait TypeRelatingDelegate<'tcx> {
     /// satisfied for the two types to be related. `sub` and `sup` may
     /// be regions from the type or new variables created through the
     /// delegate.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        info: ty::VarianceDiagInfo<'tcx>,
+    );
 
     fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
 
@@ -138,7 +145,14 @@ pub fn new(
         delegate: D,
         ambient_variance: ty::Variance,
     ) -> Self {
-        Self { infcx, delegate, ambient_variance, a_scopes: vec![], b_scopes: vec![] }
+        Self {
+            infcx,
+            delegate,
+            ambient_variance,
+            ambient_variance_info: ty::VarianceDiagInfo::default(),
+            a_scopes: vec![],
+            b_scopes: vec![],
+        }
     }
 
     fn ambient_covariance(&self) -> bool {
@@ -239,10 +253,15 @@ fn replace_bound_region(
 
     /// Push a new outlives requirement into our output set of
     /// constraints.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        info: ty::VarianceDiagInfo<'tcx>,
+    ) {
         debug!("push_outlives({:?}: {:?})", sup, sub);
 
-        self.delegate.push_outlives(sup, sub);
+        self.delegate.push_outlives(sup, sub, info);
     }
 
     /// Relate a projection type and some value type lazily. This will always
@@ -490,6 +509,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -497,6 +517,7 @@ fn relate_with_variance<T: Relate<'tcx>>(
 
         let old_ambient_variance = self.ambient_variance;
         self.ambient_variance = self.ambient_variance.xform(variance);
+        self.ambient_variance_info = self.ambient_variance_info.clone().xform(info);
 
         debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
 
@@ -574,12 +595,12 @@ fn regions(
 
         if self.ambient_covariance() {
             // Covariance: a <= b. Hence, `b: a`.
-            self.push_outlives(v_b, v_a);
+            self.push_outlives(v_b, v_a, self.ambient_variance_info.clone());
         }
 
         if self.ambient_contravariance() {
             // Contravariant: b <= a. Hence, `a: b`.
-            self.push_outlives(v_a, v_b);
+            self.push_outlives(v_a, v_b, self.ambient_variance_info.clone());
         }
 
         Ok(a)
@@ -835,6 +856,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index bf5f328233dfd7832ba421924214d53fec58df8d..b3131936ae06608210a7bedab490e1bf38859c58 100644 (file)
@@ -62,6 +62,7 @@ fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index 8e2c79701af90d76d48d6979e23a08c4f7fd35ea..02ff1b9f4d655ff15fc191617eccd1439e7dfd29 100644 (file)
@@ -46,6 +46,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
+        _: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index 5da2aab409376636018087cd8deb51d334c9d20d..b58c92b8415175c748752757eed4cff4ef04fb75 100644 (file)
@@ -71,7 +71,7 @@
     ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
     GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
     PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
-    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts,
+    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
 };
 pub use self::trait_def::TraitDef;
 
index b6f93c9bd59e79bbe51efb25aefa106fdcea6e10..872d12cac9384ab086d829be8e856facb9c1c643 100644 (file)
@@ -67,6 +67,7 @@ fn relate_item_substs(
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T>;
@@ -111,24 +112,23 @@ fn relate<R: TypeRelation<'tcx>>(
 ///////////////////////////////////////////////////////////////////////////
 // Relate impls
 
-impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
-    fn relate<R: TypeRelation<'tcx>>(
-        relation: &mut R,
-        a: ty::TypeAndMut<'tcx>,
-        b: ty::TypeAndMut<'tcx>,
-    ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
-        debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
-        if a.mutbl != b.mutbl {
-            Err(TypeError::Mutability)
-        } else {
-            let mutbl = a.mutbl;
-            let variance = match mutbl {
-                ast::Mutability::Not => ty::Covariant,
-                ast::Mutability::Mut => ty::Invariant,
-            };
-            let ty = relation.relate_with_variance(variance, a.ty, b.ty)?;
-            Ok(ty::TypeAndMut { ty, mutbl })
-        }
+fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
+    relation: &mut R,
+    a: ty::TypeAndMut<'tcx>,
+    b: ty::TypeAndMut<'tcx>,
+    kind: ty::VarianceDiagMutKind,
+) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
+    debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
+    if a.mutbl != b.mutbl {
+        Err(TypeError::Mutability)
+    } else {
+        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 }),
+        };
+        let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
+        Ok(ty::TypeAndMut { ty, mutbl })
     }
 }
 
@@ -142,7 +142,7 @@ pub fn relate_substs<R: TypeRelation<'tcx>>(
 
     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, a, b)
+        relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b)
     });
 
     tcx.mk_substs(params)
@@ -177,7 +177,12 @@ fn relate<R: TypeRelation<'tcx>>(
                 if is_output {
                     relation.relate(a, b)
                 } else {
-                    relation.relate_with_variance(ty::Contravariant, a, b)
+                    relation.relate_with_variance(
+                        ty::Contravariant,
+                        ty::VarianceDiagInfo::default(),
+                        a,
+                        b,
+                    )
                 }
             })
             .enumerate()
@@ -251,8 +256,18 @@ fn relate<R: TypeRelation<'tcx>>(
                 b.item_def_id,
             )))
         } else {
-            let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?;
-            let substs = relation.relate_with_variance(ty::Invariant, a.substs, b.substs)?;
+            let ty = relation.relate_with_variance(
+                ty::Invariant,
+                ty::VarianceDiagInfo::default(),
+                a.ty,
+                b.ty,
+            )?;
+            let substs = relation.relate_with_variance(
+                ty::Invariant,
+                ty::VarianceDiagInfo::default(),
+                a.substs,
+                b.substs,
+            )?;
             Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
         }
     }
@@ -364,7 +379,12 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
 
         (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => {
             let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
-                relation.relate_with_variance(ty::Contravariant, a_region, b_region)
+                relation.relate_with_variance(
+                    ty::Contravariant,
+                    ty::VarianceDiagInfo::default(),
+                    a_region,
+                    b_region,
+                )
             })?;
             Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound))
         }
@@ -398,15 +418,20 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
         }
 
         (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
-            let mt = relation.relate(a_mt, b_mt)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?;
             Ok(tcx.mk_ptr(mt))
         }
 
         (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
-            let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?;
+            let r = relation.relate_with_variance(
+                ty::Contravariant,
+                ty::VarianceDiagInfo::default(),
+                a_r,
+                b_r,
+            )?;
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
-            let mt = relation.relate(a_mt, b_mt)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?;
             Ok(tcx.mk_ref(r, mt))
         }
 
@@ -536,8 +561,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
             if au.def == bu.def && au.promoted == bu.promoted =>
         {
-            let substs =
-                relation.relate_with_variance(ty::Variance::Invariant, au.substs, bu.substs)?;
+            let substs = relation.relate_with_variance(
+                ty::Variance::Invariant,
+                ty::VarianceDiagInfo::default(),
+                au.substs,
+                bu.substs,
+            )?;
             return Ok(tcx.mk_const(ty::Const {
                 val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: au.def,
index c1f71fbbfa41ad485012b9942faf2ebf766f6779..1d9ff512288db9b05e140f6f4d224fa35b60f36a 100644 (file)
@@ -2181,3 +2181,55 @@ pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
         }
     }
 }
+
+/// Extra information about why we ended up with a particular variance.
+/// This is only used to add more information to error messages, and
+/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
+/// may lead to confusing notes in error messages, it will never cause
+/// a miscompilation or unsoundness.
+///
+/// When in doubt, use `VarianceDiagInfo::default()`
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagInfo<'tcx> {
+    /// No additional information - this is the default.
+    /// We will not add any additional information to error messages.
+    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`).
+        ty: Ty<'tcx>,
+    },
+}
+
+#[derive(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
+        match self {
+            VarianceDiagInfo::None => other,
+            VarianceDiagInfo::Mut { .. } => self,
+        }
+    }
+}
+
+impl<'tcx> Default for VarianceDiagInfo<'tcx> {
+    fn default() -> Self {
+        Self::None
+    }
+}
index f3f6b8c10da7ce1d47949d5acc341b4bf5f3b605..9e4cfb2cc00fa0f541e51649c229d0c0f18da8fb 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_data_structures::graph;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
 use rustc_span::DUMMY_SP;
 
 use crate::borrow_check::{
@@ -26,8 +26,8 @@
 /// Marker trait that controls whether a `R1: R2` constraint
 /// represents an edge `R1 -> R2` or `R2 -> R1`.
 crate trait ConstraintGraphDirecton: Copy + 'static {
-    fn start_region(c: &OutlivesConstraint) -> RegionVid;
-    fn end_region(c: &OutlivesConstraint) -> RegionVid;
+    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid;
+    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid;
     fn is_normal() -> bool;
 }
 
 crate struct Normal;
 
 impl ConstraintGraphDirecton for Normal {
-    fn start_region(c: &OutlivesConstraint) -> RegionVid {
+    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sup
     }
 
-    fn end_region(c: &OutlivesConstraint) -> RegionVid {
+    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sub
     }
 
@@ -60,11 +60,11 @@ fn is_normal() -> bool {
 crate struct Reverse;
 
 impl ConstraintGraphDirecton for Reverse {
-    fn start_region(c: &OutlivesConstraint) -> RegionVid {
+    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sub
     }
 
-    fn end_region(c: &OutlivesConstraint) -> RegionVid {
+    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sup
     }
 
@@ -78,7 +78,7 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
     /// R2` is treated as an edge `R1 -> R2`. We use this graph to
     /// construct SCCs for region inference but also for error
     /// reporting.
-    crate fn new(direction: D, set: &OutlivesConstraintSet, num_region_vars: usize) -> Self {
+    crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self {
         let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars);
         let mut next_constraints = IndexVec::from_elem(None, &set.outlives);
 
@@ -96,21 +96,21 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
     /// Given the constraint set from which this graph was built
     /// creates a region graph so that you can iterate over *regions*
     /// and not constraints.
-    crate fn region_graph<'rg>(
+    crate fn region_graph<'rg, 'tcx>(
         &'rg self,
-        set: &'rg OutlivesConstraintSet,
+        set: &'rg OutlivesConstraintSet<'tcx>,
         static_region: RegionVid,
-    ) -> RegionGraph<'rg, D> {
+    ) -> RegionGraph<'rg, 'tcx, D> {
         RegionGraph::new(set, self, static_region)
     }
 
     /// Given a region `R`, iterate over all constraints `R: R1`.
-    crate fn outgoing_edges<'a>(
+    crate fn outgoing_edges<'a, 'tcx>(
         &'a self,
         region_sup: RegionVid,
-        constraints: &'a OutlivesConstraintSet,
+        constraints: &'a OutlivesConstraintSet<'tcx>,
         static_region: RegionVid,
-    ) -> Edges<'a, D> {
+    ) -> Edges<'a, 'tcx, D> {
         //if this is the `'static` region and the graph's direction is normal,
         //then setup the Edges iterator to return all regions #53178
         if region_sup == static_region && D::is_normal() {
@@ -129,22 +129,22 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
     }
 }
 
-crate struct Edges<'s, D: ConstraintGraphDirecton> {
+crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
     graph: &'s ConstraintGraph<D>,
-    constraints: &'s OutlivesConstraintSet,
+    constraints: &'s OutlivesConstraintSet<'tcx>,
     pointer: Option<OutlivesConstraintIndex>,
     next_static_idx: Option<usize>,
     static_region: RegionVid,
 }
 
-impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
-    type Item = OutlivesConstraint;
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
+    type Item = OutlivesConstraint<'tcx>;
 
     fn next(&mut self) -> Option<Self::Item> {
         if let Some(p) = self.pointer {
             self.pointer = self.graph.next_constraints[p];
 
-            Some(self.constraints[p])
+            Some(self.constraints[p].clone())
         } else if let Some(next_static_idx) = self.next_static_idx {
             self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
                 None
@@ -157,6 +157,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 sub: next_static_idx.into(),
                 locations: Locations::All(DUMMY_SP),
                 category: ConstraintCategory::Internal,
+                variance_info: VarianceDiagInfo::default(),
             })
         } else {
             None
@@ -167,19 +168,19 @@ fn next(&mut self) -> Option<Self::Item> {
 /// This struct brings together a constraint set and a (normal, not
 /// reverse) constraint graph. It implements the graph traits and is
 /// usd for doing the SCC computation.
-crate struct RegionGraph<'s, D: ConstraintGraphDirecton> {
-    set: &'s OutlivesConstraintSet,
+crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> {
+    set: &'s OutlivesConstraintSet<'tcx>,
     constraint_graph: &'s ConstraintGraph<D>,
     static_region: RegionVid,
 }
 
-impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> {
     /// Creates a "dependency graph" where each region constraint `R1:
     /// R2` is treated as an edge `R1 -> R2`. We use this graph to
     /// construct SCCs for region inference but also for error
     /// reporting.
     crate fn new(
-        set: &'s OutlivesConstraintSet,
+        set: &'s OutlivesConstraintSet<'tcx>,
         constraint_graph: &'s ConstraintGraph<D>,
         static_region: RegionVid,
     ) -> Self {
@@ -188,18 +189,18 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
 
     /// Given a region `R`, iterate over all regions `R1` such that
     /// there exists a constraint `R: R1`.
-    crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> {
+    crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> {
         Successors {
             edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
         }
     }
 }
 
-crate struct Successors<'s, D: ConstraintGraphDirecton> {
-    edges: Edges<'s, D>,
+crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> {
+    edges: Edges<'s, 'tcx, D>,
 }
 
-impl<'s, D: ConstraintGraphDirecton> Iterator for Successors<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> {
     type Item = RegionVid;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -207,23 +208,26 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
-impl<'s, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
     type Node = RegionVid;
 }
 
-impl<'s, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
     fn num_nodes(&self) -> usize {
         self.constraint_graph.first_constraints.len()
     }
 }
 
-impl<'s, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
     fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
         self.outgoing_regions(node)
     }
 }
 
-impl<'s, 'graph, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> for RegionGraph<'s, D> {
+impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph>
+    for RegionGraph<'s, 'tcx, D>
+{
     type Item = RegionVid;
-    type Iter = Successors<'graph, D>;
+    // FIXME - why can't this be `'graph, 'tcx`
+    type Iter = Successors<'graph, 'graph, D>;
 }
index 3772b7d8f986db68d79db028e181c9f8c6558dff..b944479ca456b387fe7dd23c44e1be17a2840308 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
 use std::fmt;
 use std::ops::Index;
 
 /// a unique `OutlivesConstraintIndex` and you can index into the set
 /// (`constraint_set[i]`) to access the constraint details.
 #[derive(Clone, Default)]
-crate struct OutlivesConstraintSet {
-    outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint>,
+crate struct OutlivesConstraintSet<'tcx> {
+    outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>,
 }
 
-impl OutlivesConstraintSet {
-    crate fn push(&mut self, constraint: OutlivesConstraint) {
+impl<'tcx> OutlivesConstraintSet<'tcx> {
+    crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
         debug!(
             "OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
             constraint.sup, constraint.sub, constraint.locations
@@ -59,21 +59,21 @@ impl OutlivesConstraintSet {
         Sccs::new(region_graph)
     }
 
-    crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint> {
+    crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
         &self.outlives
     }
 }
 
-impl Index<OutlivesConstraintIndex> for OutlivesConstraintSet {
-    type Output = OutlivesConstraint;
+impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
+    type Output = OutlivesConstraint<'tcx>;
 
     fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output {
         &self.outlives[i]
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct OutlivesConstraint {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct OutlivesConstraint<'tcx> {
     // NB. The ordering here is not significant for correctness, but
     // it is for convenience. Before we dump the constraints in the
     // debugging logs, we sort them, and we'd like the "super region"
@@ -89,11 +89,18 @@ pub struct OutlivesConstraint {
 
     /// What caused this constraint?
     pub category: ConstraintCategory,
+
+    /// Variance diagnostic information
+    pub variance_info: VarianceDiagInfo<'tcx>,
 }
 
-impl fmt::Debug for OutlivesConstraint {
+impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(formatter, "({:?}: {:?}) due to {:?}", self.sup, self.sub, self.locations)
+        write!(
+            formatter,
+            "({:?}: {:?}) due to {:?} ({:?})",
+            self.sup, self.sub, self.locations, self.variance_info
+        )
     }
 }
 
index 1b0cae51d585df974fcad6604a62dd800596ab75..e9f1ecb9bbc81dec0af6123ecb6402f742d69c55 100644 (file)
@@ -15,6 +15,7 @@
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
+use crate::borrow_check::region_infer::BlameConstraint;
 use crate::borrow_check::{
     borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
     WriteKind,
@@ -289,12 +290,13 @@ fn free_region_constraint_info(
         borrow_region: RegionVid,
         outlived_region: RegionVid,
     ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
-        let (category, from_closure, span) = self.regioncx.best_blame_constraint(
-            &self.body,
-            borrow_region,
-            NllRegionVariableOrigin::FreeRegion,
-            |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
-        );
+        let BlameConstraint { category, from_closure, span, variance_info: _ } =
+            self.regioncx.best_blame_constraint(
+                &self.body,
+                borrow_region,
+                NllRegionVariableOrigin::FreeRegion,
+                |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
+            );
 
         let outlived_fr_name = self.give_region_a_name(outlived_region);
 
index 8665ef06126a1b395c80fc8d71cbbc4e13b5352e..feb7672f650ecdd1338e55b04693bd211db9d2b8 100644 (file)
@@ -13,6 +13,7 @@
 
 use crate::util::borrowck_errors;
 
+use crate::borrow_check::region_infer::BlameConstraint;
 use crate::borrow_check::{
     nll::ConstraintDescription,
     region_infer::{values::RegionElement, TypeTest},
@@ -275,12 +276,12 @@ pub(in crate::borrow_check) fn report_region_error(
     ) {
         debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
 
-        let (category, _, span) =
+        let BlameConstraint { category, span, variance_info, from_closure: _ } =
             self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
                 self.regioncx.provides_universal_region(r, fr, outlived_fr)
             });
 
-        debug!("report_region_error: category={:?} {:?}", category, span);
+        debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info);
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
             let nice = NiceRegionError::new_from_span(self.infcx, span, o, f);
@@ -309,7 +310,7 @@ pub(in crate::borrow_check) fn report_region_error(
             span,
         };
 
-        let diag = match (category, fr_is_local, outlived_fr_is_local) {
+        let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
             (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
                 self.report_fnmut_error(&errci, kind)
             }
@@ -332,6 +333,19 @@ pub(in crate::borrow_check) fn report_region_error(
             }
         };
 
+        match variance_info {
+            ty::VarianceDiagInfo::None => {}
+            ty::VarianceDiagInfo::Mut { kind, ty } => {
+                let kind_name = match kind {
+                    ty::VarianceDiagMutKind::Ref => "reference",
+                    ty::VarianceDiagMutKind::RawPtr => "pointer",
+                };
+                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.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
+            }
+        }
+
         diag.buffer(&mut self.errors_buffer);
     }
 
index 5892ef37ebacb56df38b1306bfae5f16a7bc3eed..213ebff12abc0b65940e94f9845232c3c83cfa95 100644 (file)
@@ -74,7 +74,7 @@ fn for_each_constraint(
         let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
         constraints.sort();
         for constraint in &constraints {
-            let OutlivesConstraint { sup, sub, locations, category } = constraint;
+            let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
             let (name, arg) = match locations {
                 Locations::All(span) => {
                     ("All", tcx.sess.source_map().span_to_embeddable_string(*span))
index 7156612f4730f05d3917bb7b8b2b5e79bda3a27e..b944d74e6f23137b3040974955e291d9ce70e26d 100644 (file)
@@ -35,7 +35,7 @@ struct RawConstraints<'a, 'tcx> {
 
 impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
     type Node = RegionVid;
-    type Edge = OutlivesConstraint;
+    type Edge = OutlivesConstraint<'tcx>;
 
     fn graph_id(&'this self) -> dot::Id<'this> {
         dot::Id::new("RegionInferenceContext").unwrap()
@@ -49,31 +49,31 @@ fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> {
     fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
         dot::LabelText::LabelStr(format!("{:?}", n).into())
     }
-    fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
+    fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> {
         dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
     }
 }
 
 impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
     type Node = RegionVid;
-    type Edge = OutlivesConstraint;
+    type Edge = OutlivesConstraint<'tcx>;
 
     fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
         let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
         vids.into()
     }
-    fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
+    fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> {
         (&self.regioncx.constraints.outlives().raw[..]).into()
     }
 
     // Render `a: b` as `a -> b`, indicating the flow
     // of data during inference.
 
-    fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+    fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
         edge.sup
     }
 
-    fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+    fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
         edge.sub
     }
 }
index f4d78ac04cb029832ac6bf40d8f19033c6e825a4..dded7a7e3cf99e47166e2997d7c364369866490e 100644 (file)
@@ -54,7 +54,7 @@ pub struct RegionInferenceContext<'tcx> {
     liveness_constraints: LivenessValues<RegionVid>,
 
     /// The outlives constraints computed by the type-check.
-    constraints: Frozen<OutlivesConstraintSet>,
+    constraints: Frozen<OutlivesConstraintSet<'tcx>>,
 
     /// The constraint-set, but in graph form, making it easy to traverse
     /// the constraints adjacent to a particular region. Used to construct
@@ -227,10 +227,10 @@ enum RegionRelationCheckResult {
     Error,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum Trace {
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum Trace<'tcx> {
     StartRegion,
-    FromOutlivesConstraint(OutlivesConstraint),
+    FromOutlivesConstraint(OutlivesConstraint<'tcx>),
     NotVisited,
 }
 
@@ -247,7 +247,7 @@ pub(in crate::borrow_check) fn new(
         universal_regions: Rc<UniversalRegions<'tcx>>,
         placeholder_indices: Rc<PlaceholderIndices>,
         universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-        outlives_constraints: OutlivesConstraintSet,
+        outlives_constraints: OutlivesConstraintSet<'tcx>,
         member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
@@ -1750,20 +1750,35 @@ fn check_member_constraints(
     crate fn retrieve_closure_constraint_info(
         &self,
         body: &Body<'tcx>,
-        constraint: &OutlivesConstraint,
-    ) -> (ConstraintCategory, bool, Span) {
+        constraint: &OutlivesConstraint<'tcx>,
+    ) -> BlameConstraint<'tcx> {
         let loc = match constraint.locations {
-            Locations::All(span) => return (constraint.category, false, span),
+            Locations::All(span) => {
+                return BlameConstraint {
+                    category: constraint.category,
+                    from_closure: false,
+                    span,
+                    variance_info: constraint.variance_info.clone(),
+                };
+            }
             Locations::Single(loc) => loc,
         };
 
         let opt_span_category =
             self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
-        opt_span_category.map(|&(category, span)| (category, true, span)).unwrap_or((
-            constraint.category,
-            false,
-            body.source_info(loc).span,
-        ))
+        opt_span_category
+            .map(|&(category, span)| BlameConstraint {
+                category,
+                from_closure: true,
+                span: span,
+                variance_info: constraint.variance_info.clone(),
+            })
+            .unwrap_or(BlameConstraint {
+                category: constraint.category,
+                from_closure: false,
+                span: body.source_info(loc).span,
+                variance_info: constraint.variance_info.clone(),
+            })
     }
 
     /// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
@@ -1774,9 +1789,10 @@ fn check_member_constraints(
         fr1_origin: NllRegionVariableOrigin,
         fr2: RegionVid,
     ) -> (ConstraintCategory, Span) {
-        let (category, _, span) = self.best_blame_constraint(body, fr1, fr1_origin, |r| {
-            self.provides_universal_region(r, fr1, fr2)
-        });
+        let BlameConstraint { category, span, .. } =
+            self.best_blame_constraint(body, fr1, fr1_origin, |r| {
+                self.provides_universal_region(r, fr1, fr2)
+            });
         (category, span)
     }
 
@@ -1792,7 +1808,7 @@ fn check_member_constraints(
         &self,
         from_region: RegionVid,
         target_test: impl Fn(RegionVid) -> bool,
-    ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> {
+    ) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)> {
         let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
         context[from_region] = Trace::StartRegion;
 
@@ -1816,14 +1832,14 @@ fn check_member_constraints(
                 let mut result = vec![];
                 let mut p = r;
                 loop {
-                    match context[p] {
+                    match context[p].clone() {
                         Trace::NotVisited => {
                             bug!("found unvisited region {:?} on path to {:?}", p, r)
                         }
 
                         Trace::FromOutlivesConstraint(c) => {
-                            result.push(c);
                             p = c.sup;
+                            result.push(c);
                         }
 
                         Trace::StartRegion => {
@@ -1846,7 +1862,7 @@ fn check_member_constraints(
 
             // Always inline this closure because it can be hot.
             let mut handle_constraint = #[inline(always)]
-            |constraint: OutlivesConstraint| {
+            |constraint: OutlivesConstraint<'tcx>| {
                 debug_assert_eq!(constraint.sup, r);
                 let sub_region = constraint.sub;
                 if let Trace::NotVisited = context[sub_region] {
@@ -1870,6 +1886,7 @@ fn check_member_constraints(
                     sub: constraint.min_choice,
                     locations: Locations::All(p_c.definition_span),
                     category: ConstraintCategory::OpaqueType,
+                    variance_info: ty::VarianceDiagInfo::default(),
                 };
                 handle_constraint(constraint);
             }
@@ -1967,7 +1984,7 @@ fn check_member_constraints(
         from_region: RegionVid,
         from_region_origin: NllRegionVariableOrigin,
         target_test: impl Fn(RegionVid) -> bool,
-    ) -> (ConstraintCategory, bool, Span) {
+    ) -> BlameConstraint<'tcx> {
         debug!(
             "best_blame_constraint(from_region={:?}, from_region_origin={:?})",
             from_region, from_region_origin
@@ -1979,7 +1996,7 @@ fn check_member_constraints(
         debug!(
             "best_blame_constraint: path={:#?}",
             path.iter()
-                .map(|&c| format!(
+                .map(|c| format!(
                     "{:?} ({:?}: {:?})",
                     c,
                     self.constraint_sccs.scc(c.sup),
@@ -1989,13 +2006,18 @@ fn check_member_constraints(
         );
 
         // Classify each of the constraints along the path.
-        let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path
+        let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
             .iter()
             .map(|constraint| {
                 if constraint.category == ConstraintCategory::ClosureBounds {
                     self.retrieve_closure_constraint_info(body, &constraint)
                 } else {
-                    (constraint.category, false, constraint.locations.span(body))
+                    BlameConstraint {
+                        category: constraint.category,
+                        from_closure: false,
+                        span: constraint.locations.span(body),
+                        variance_info: constraint.variance_info.clone(),
+                    }
                 }
             })
             .collect();
@@ -2067,12 +2089,12 @@ fn check_member_constraints(
         };
 
         let find_region = |i: &usize| {
-            let constraint = path[*i];
+            let constraint = &path[*i];
 
             let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
 
             if blame_source {
-                match categorized_path[*i].0 {
+                match categorized_path[*i].category {
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
@@ -2083,7 +2105,7 @@ fn check_member_constraints(
                     _ => constraint_sup_scc != target_scc,
                 }
             } else {
-                match categorized_path[*i].0 {
+                match categorized_path[*i].category {
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
@@ -2103,37 +2125,42 @@ fn check_member_constraints(
 
         if let Some(i) = best_choice {
             if let Some(next) = categorized_path.get(i + 1) {
-                if matches!(categorized_path[i].0, ConstraintCategory::Return(_))
-                    && next.0 == ConstraintCategory::OpaqueType
+                if matches!(categorized_path[i].category, ConstraintCategory::Return(_))
+                    && next.category == ConstraintCategory::OpaqueType
                 {
                     // The return expression is being influenced by the return type being
                     // impl Trait, point at the return type and not the return expr.
-                    return *next;
+                    return next.clone();
                 }
             }
 
-            if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) {
+            if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal)
+            {
                 let field = categorized_path.iter().find_map(|p| {
-                    if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None }
+                    if let ConstraintCategory::ClosureUpvar(f) = p.category {
+                        Some(f)
+                    } else {
+                        None
+                    }
                 });
 
                 if let Some(field) = field {
-                    categorized_path[i].0 =
+                    categorized_path[i].category =
                         ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
                 }
             }
 
-            return categorized_path[i];
+            return categorized_path[i].clone();
         }
 
         // If that search fails, that is.. unusual. Maybe everything
         // is in the same SCC or something. In that case, find what
         // appears to be the most interesting point to report to the
         // user via an even more ad-hoc guess.
-        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+        categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
         debug!("`: sorted_path={:#?}", categorized_path);
 
-        *categorized_path.first().unwrap()
+        categorized_path.remove(0)
     }
 }
 
@@ -2228,3 +2255,11 @@ fn apply_requirements(
             .collect()
     }
 }
+
+#[derive(Clone, Debug)]
+pub struct BlameConstraint<'tcx> {
+    pub category: ConstraintCategory,
+    pub from_closure: bool,
+    pub span: Span,
+    pub variance_info: ty::VarianceDiagInfo<'tcx>,
+}
index 8513e5e531bd7e88b7cfe607fc6c43800a908a2c..eb11b9371433d145a24cac55f8738877d39ecb25 100644 (file)
@@ -143,6 +143,7 @@ fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
             category: self.category,
             sub,
             sup,
+            variance_info: ty::VarianceDiagInfo::default(),
         });
     }
 
index bddcd34ed3e47e97762477b4bcc1f625acdbb5fa..a34ae281b70dfdd547ed652226264299e0f37a1f 100644 (file)
@@ -107,7 +107,7 @@ fn compute_live_locals(
 fn regions_that_outlive_free_regions(
     num_region_vars: usize,
     universal_regions: &UniversalRegions<'tcx>,
-    constraint_set: &OutlivesConstraintSet,
+    constraint_set: &OutlivesConstraintSet<'tcx>,
 ) -> FxHashSet<RegionVid> {
     // Build a graph of the outlives constraints thus far. This is
     // a reverse graph, so for each constraint `R1: R2` we have an
index d27fcb2f26f19bce0f529f2b278523973baf0594..e294f128f2e142eb789e3a41051fc6aebbb97e91 100644 (file)
@@ -226,7 +226,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
         let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
         let location_table = cx.location_table;
         facts.outlives.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map(
-            |constraint: &OutlivesConstraint| {
+            |constraint: &OutlivesConstraint<'_>| {
                 if let Some(from_location) = constraint.locations.from_location() {
                     Either::Left(iter::once((
                         constraint.sup,
@@ -572,7 +572,7 @@ fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Locatio
 
         let locations = location.to_locations();
         for constraint in constraints.outlives().iter() {
-            let mut constraint = *constraint;
+            let mut constraint = constraint.clone();
             constraint.locations = locations;
             if let ConstraintCategory::Return(_)
             | ConstraintCategory::UseAsConst
@@ -862,7 +862,7 @@ struct BorrowCheckContext<'a, 'tcx> {
     /// hence it must report on their liveness constraints.
     crate liveness_constraints: LivenessValues<RegionVid>,
 
-    crate outlives_constraints: OutlivesConstraintSet,
+    crate outlives_constraints: OutlivesConstraintSet<'tcx>,
 
     crate member_constraints: MemberConstraintSet<'tcx, RegionVid>,
 
@@ -2535,6 +2535,7 @@ fn add_reborrow_constraint(
                                 sub: borrow_region.to_region_vid(),
                                 locations: location.to_locations(),
                                 category,
+                                variance_info: ty::VarianceDiagInfo::default(),
                             });
 
                             match mutbl {
index 249945f04b7b05748410f88697ca187fd6872bd2..f97252a117a6f018eec4cc881f37a39ceb94f727 100644 (file)
@@ -94,7 +94,12 @@ fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<
         )
     }
 
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        info: ty::VarianceDiagInfo<'tcx>,
+    ) {
         if let Some(borrowck_context) = &mut self.borrowck_context {
             let sub = borrowck_context.universal_regions.to_region_vid(sub);
             let sup = borrowck_context.universal_regions.to_region_vid(sup);
@@ -103,6 +108,7 @@ fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
                 sub,
                 locations: self.locations,
                 category: self.category,
+                variance_info: info,
             });
         }
     }
index 12a36976f1d4b2f93ba1ffb0b1428d60e492a5fc..1da17bddcb777c3b044f4160beb686b8fddf4172 100644 (file)
@@ -15,6 +15,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
+#![feature(format_args_capture)]
 #![feature(iter_zip)]
 #![feature(never_type)]
 #![feature(map_try_insert)]
index de6336b254b3f49c643b3a3dae72a387d076a1a2..01276495c185aea81546f90973c0c04a3db91852 100644 (file)
@@ -310,6 +310,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index dd67514d02aa43f617248d24f69717524cc6ba7b..cf73403bbae0755606200b12da834029deec0cf7 100644 (file)
@@ -64,6 +64,10 @@ LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     ap0 = &mut ap1;
    |     ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+   = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+   = note: mutable references are invariant over their type parameter
+   = 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
@@ -74,6 +78,10 @@ LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     ap0 = &mut ap1;
    |     ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
+   |
+   = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error[E0597]: `ap1` does not live long enough
   --> $DIR/variadic-ffi-4.rs:28:11
index 1658efa28bf307ff7661cbe1bd1df807758a8035..1dc29d2088cea353ac262aaff3062ab176cc63fc 100644 (file)
@@ -9,6 +9,9 @@ LL |         match self.0 { ref mut x => x }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
index dc227a36566e6d68345cddd6c5340a2156704822..8b87c3da28b02f946a700dc55b004a272b0a26b1 100644 (file)
@@ -10,6 +10,9 @@ LL |         x
    |         ^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
index 39fd98f7151a000eb5f8490a71a63ad2d38ba2ef..ccb3d33ac40647fe14f45cbfcf3a6fe4e85aa11f 100644 (file)
@@ -34,6 +34,9 @@ LL |     x
    |     ^ 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 a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-coercions.rs:13:5
@@ -47,6 +50,9 @@ LL |     x
    |     ^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = 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
 
index f350b861eb6d2447c690d0852f9d4df910fc75ba..b488af820b86d78344fff37d05dab2357098cd1b 100644 (file)
@@ -9,6 +9,9 @@ LL |     x == y;
    |     ^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-comparisons.rs:6:10
@@ -21,6 +24,9 @@ LL |     x == y;
    |          ^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = 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
 
@@ -35,6 +41,9 @@ LL |     x == y;
    |     ^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-comparisons.rs:12:10
@@ -47,6 +56,9 @@ LL |     x == y;
    |          ^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = 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
 
@@ -61,6 +73,9 @@ LL |     f == g;
    |     ^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-comparisons.rs:18:10
@@ -73,6 +88,9 @@ LL |     f == g;
    |          ^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = 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
 
index 695f5506d5e38aadb36977a37f8e02c128ef450d..4ddea2c27b2a634263b583da8368661d2d09a78b 100644 (file)
@@ -23,6 +23,9 @@ LL |     a(x, y);
    |     ^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &isize
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: higher-ranked subtype error
   --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
index a28f7aa3e08ca73b14f95ae8b84d032875f333cd..a9cf128bb621a4bdec7167e1dee1573b058c6597 100644 (file)
@@ -23,6 +23,9 @@ LL |     a(x, y, z);
    |     ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &isize
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: higher-ranked subtype error
   --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
index 37f7fcf2e331a882e5a4e2594f7c14a5d1454f50..db86572f1cf73a4c1ddde1973abfd164a76976c0 100644 (file)
@@ -23,6 +23,9 @@ LL |     a(x, y);
    |     ^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &isize
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: higher-ranked subtype error
   --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
index f92923a112584138fcfd35dd36c0da70356438b5..bf325d5601348697cdedd2dffb7e52b1ac020544 100644 (file)
@@ -10,6 +10,9 @@ LL |     x
    |     ^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to dyn Dummy
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/regions-trait-object-subtyping.rs:22:5
@@ -23,6 +26,9 @@ LL |     x
    |     ^ returning this value requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to dyn Dummy
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to 2 previous errors