Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
@@ -660,7 +660,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
)
}

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,
25 changes: 20 additions & 5 deletions compiler/rustc_infer/src/infer/combine.rs
Original file line number Diff line number Diff line change
@@ -371,9 +371,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
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 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
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 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
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 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
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 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
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 }),
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/equate.rs
Original file line number Diff line number Diff line change
@@ -59,6 +59,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
_info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/infer/glb.rs
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
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 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
// 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)
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/infer/lub.rs
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
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 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
// 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)
}
}
34 changes: 28 additions & 6 deletions compiler/rustc_infer/src/infer/nll_relate/mod.rs
Original file line number Diff line number Diff line change
@@ -55,6 +55,8 @@ where
/// - 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 @@ where
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 @@ where

/// 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,13 +509,15 @@ where
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b);

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 @@ where

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 @@ where
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
_info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/sub.rs
Original file line number Diff line number Diff line change
@@ -62,6 +62,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
_info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/_match.rs
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ impl TypeRelation<'tcx> for Match<'tcx> {
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
_: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ pub use self::sty::{
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;

85 changes: 57 additions & 28 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
@@ -67,6 +67,7 @@ pub trait TypeRelation<'tcx>: Sized {
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 @@ pub trait Relate<'tcx>: TypeFoldable<'tcx> + Copy {
///////////////////////////////////////////////////////////////////////////
// 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 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'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 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'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,
52 changes: 52 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
@@ -2181,3 +2181,55 @@ impl<'tcx> TyS<'tcx> {
}
}
}

/// 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
}
}
68 changes: 36 additions & 32 deletions compiler/rustc_mir/src/borrow_check/constraints/graph.rs
Original file line number Diff line number Diff line change
@@ -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 @@ crate type ReverseConstraintGraph = ConstraintGraph<Reverse>;
/// 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;
}

@@ -39,11 +39,11 @@ crate trait ConstraintGraphDirecton: Copy + 'static {
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 @@ impl ConstraintGraphDirecton for Normal {
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 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
sub: next_static_idx.into(),
locations: Locations::All(DUMMY_SP),
category: ConstraintCategory::Internal,
variance_info: VarianceDiagInfo::default(),
})
} else {
None
@@ -167,19 +168,19 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
/// 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,42 +189,45 @@ 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> {
self.edges.next().map(|c| D::end_region(&c))
}
}

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>;
}
31 changes: 19 additions & 12 deletions compiler/rustc_mir/src/borrow_check/constraints/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

@@ -14,12 +14,12 @@ crate mod graph;
/// 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
)
}
}

Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt};
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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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);

20 changes: 17 additions & 3 deletions compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ use rustc_span::Span;

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 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) {
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 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
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 @@ 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",
};
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);
}

Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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))
12 changes: 6 additions & 6 deletions compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
Original file line number Diff line number Diff line change
@@ -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 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
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
}
}
107 changes: 71 additions & 36 deletions compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
Original file line number Diff line number Diff line change
@@ -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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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 @@ impl<'tcx> RegionInferenceContext<'tcx> {

// 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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!(
"best_blame_constraint: path={:#?}",
path.iter()
.map(|&c| format!(
.map(|c| format!(
"{:?} ({:?}: {:?})",
c,
self.constraint_sccs.scc(c.sup),
@@ -1989,13 +2006,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
);

// 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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
};

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 @@ impl<'tcx> RegionInferenceContext<'tcx> {
_ => 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 @@ impl<'tcx> RegionInferenceContext<'tcx> {

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 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
.collect()
}
}

#[derive(Clone, Debug)]
pub struct BlameConstraint<'tcx> {
pub category: ConstraintCategory,
pub from_closure: bool,
pub span: Span,
pub variance_info: ty::VarianceDiagInfo<'tcx>,
}
Original file line number Diff line number Diff line change
@@ -143,6 +143,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
category: self.category,
sub,
sup,
variance_info: ty::VarianceDiagInfo::default(),
});
}

Original file line number Diff line number Diff line change
@@ -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
7 changes: 4 additions & 3 deletions compiler/rustc_mir/src/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -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 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {

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 @@ crate struct MirTypeckRegionConstraints<'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 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
category,
variance_info: ty::VarianceDiagInfo::default(),
});

match mutbl {
8 changes: 7 additions & 1 deletion compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
@@ -94,7 +94,12 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
)
}

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 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
sub,
locations: self.locations,
category: self.category,
variance_info: info,
});
}
}
1 change: 1 addition & 0 deletions compiler/rustc_mir/src/lib.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ Rust MIR: a lowered representation of Rust.
#![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)]
1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/check/dropck.rs
Original file line number Diff line number Diff line change
@@ -310,6 +310,7 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
_info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
8 changes: 8 additions & 0 deletions src/test/ui/c-variadic/variadic-ffi-4.stderr
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions src/test/ui/match/match-ref-mut-invariance.nll.stderr
Original file line number Diff line number Diff line change
@@ -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

3 changes: 3 additions & 0 deletions src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
Original file line number Diff line number Diff line change
@@ -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

6 changes: 6 additions & 0 deletions src/test/ui/nll/type-check-pointer-coercions.stderr
Original file line number Diff line number Diff line change
@@ -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

18 changes: 18 additions & 0 deletions src/test/ui/nll/type-check-pointer-comparisons.stderr
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
Original file line number Diff line number Diff line change
@@ -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