diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2021-05-13 09:30:14 -0400 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2021-06-06 12:37:42 -0500 |
| commit | fad2242ff7bbafed5e7398e1286c3935b31f8233 (patch) | |
| tree | 8130278ea5c71d6985ede8c4e008fc86d6af2e45 /compiler/rustc_middle/src | |
| parent | 86b0bafbf1e0fab3aa433c10256919d1b6ba46ac (diff) | |
| download | rust-fad2242ff7bbafed5e7398e1286c3935b31f8233.tar.gz rust-fad2242ff7bbafed5e7398e1286c3935b31f8233.zip | |
Add variance-related information to lifetime error messages
Diffstat (limited to 'compiler/rustc_middle/src')
| -rw-r--r-- | compiler/rustc_middle/src/ty/_match.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/relate.rs | 85 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/sty.rs | 52 |
4 files changed, 111 insertions, 29 deletions
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 8e2c79701af..02ff1b9f4d6 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -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> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5da2aab4093..b58c92b8415 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b6f93c9bd59..872d12cac93 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -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, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c1f71fbbfa4..1d9ff512288 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -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 + } +} |
