Add variance-related information to lifetime error messages
This commit is contained in:
parent
86b0bafbf1
commit
fad2242ff7
@ -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,
|
||||
|
@ -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 }),
|
||||
|
@ -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> {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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> {
|
||||
|
@ -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> {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -39,11 +39,11 @@
|
||||
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>;
|
||||
}
|
||||
|
@ -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 @@
|
||||
/// 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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user