Skip to content

Commit 8c5940a

Browse files
committed
add variance support to TypeFoldable
1 parent 7b91b20 commit 8c5940a

File tree

3 files changed

+133
-13
lines changed

3 files changed

+133
-13
lines changed

src/librustc/ty/fold.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
3434
use crate::hir::def_id::DefId;
3535
use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
36+
use crate::ty::subst::SubstsRef;
3637

3738
use std::collections::BTreeMap;
3839
use std::fmt;
@@ -164,6 +165,35 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
164165
t.super_fold_with(self)
165166
}
166167

168+
#[inline]
169+
/// If `false` - the default - then `ty::Invariant` might be used instead of the
170+
/// correct variance when folding an item with a variance.
171+
///
172+
/// Otherwise, the correct variance is looked up from the tcx, which can
173+
/// be a performance and cycle hazard.
174+
fn use_variances(&self) -> bool {
175+
false
176+
}
177+
178+
#[inline]
179+
fn fold_item_substs(&mut self, item_def_id: DefId, substs: SubstsRef<'tcx>)
180+
-> Result<SubstsRef<'tcx>, Self::Error>
181+
{
182+
if self.use_variances() {
183+
let variances = self.tcx().variances_of(item_def_id);
184+
ty::subst::fold_with_variances(self, &variances, substs)
185+
} else {
186+
substs.fold_with(self)
187+
}
188+
}
189+
190+
#[inline]
191+
fn fold_with_variance<T>(&mut self, _variance: ty::Variance, t: &T) -> Result<T, Self::Error>
192+
where T : TypeFoldable<'tcx>
193+
{
194+
t.fold_with(self)
195+
}
196+
167197
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
168198
t.super_fold_with(self)
169199
}

src/librustc/ty/structural_impls.rs

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! hand, though we've recently added some macros (e.g.,
44
//! `BraceStructLiftImpl!`) to help with the tedium.
55
6+
use crate::hir;
67
use crate::mir::ProjectionKind;
78
use crate::mir::interpret::ConstValue;
89
use crate::ty::{self, Lift, Ty, TyCtxt};
@@ -12,6 +13,7 @@ use smallvec::SmallVec;
1213
use crate::mir::interpret;
1314

1415
use std::rc::Rc;
16+
use std::iter;
1517

1618
///////////////////////////////////////////////////////////////////////////
1719
// Atomic structs
@@ -770,16 +772,24 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
770772
ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)?),
771773
ty::Array(typ, sz) => ty::Array(typ.fold_with(folder)?, sz.fold_with(folder)?),
772774
ty::Slice(typ) => ty::Slice(typ.fold_with(folder)?),
773-
ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)?),
774-
ty::Dynamic(ref trait_ty, ref region) =>
775-
ty::Dynamic(trait_ty.fold_with(folder)?, region.fold_with(folder)?),
775+
ty::Adt(tid, substs) => {
776+
ty::Adt(tid, folder.fold_item_substs(tid.did, substs)?)
777+
}
778+
ty::Dynamic(ref trait_ty, ref region) => {
779+
let principal = trait_ty.fold_with(folder)?;
780+
let region_bound = folder.fold_with_variance(ty::Contravariant, region)?;
781+
ty::Dynamic(principal, region_bound)
782+
}
776783
ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)?),
777784
ty::FnDef(def_id, substs) => {
778-
ty::FnDef(def_id, substs.fold_with(folder)?)
785+
ty::FnDef(def_id, folder.fold_item_substs(def_id, substs)?)
779786
}
780787
ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)?),
781788
ty::Ref(ref r, ty, mutbl) => {
782-
ty::Ref(r.fold_with(folder)?, ty.fold_with(folder)?, mutbl)
789+
let r = folder.fold_with_variance(ty::Contravariant, r)?;
790+
// Fold the type as a TypeAndMut to get the correct variance.
791+
let mt = ty::TypeAndMut { ty, mutbl }.fold_with(folder)?;
792+
ty::Ref(r, mt.ty, mt.mutbl)
783793
}
784794
ty::Generator(did, substs, movability) => {
785795
ty::Generator(
@@ -864,9 +874,31 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
864874
}
865875
}
866876

867-
BraceStructTypeFoldableImpl! {
868-
impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
869-
ty, mutbl
877+
878+
879+
impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
880+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
881+
-> Result<Self, F::Error>
882+
{
883+
let ty::TypeAndMut { ty, mutbl } = self;
884+
let variance = match mutbl {
885+
hir::Mutability::MutImmutable => ty::Covariant,
886+
hir::Mutability::MutMutable => ty::Invariant,
887+
};
888+
889+
Ok(ty::TypeAndMut {
890+
ty: folder.fold_with_variance(variance, ty)?,
891+
mutbl: mutbl.fold_with(folder)?,
892+
})
893+
}
894+
895+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V)
896+
-> Result<(), V::Error>
897+
{
898+
let ty::TypeAndMut { ty, mutbl } = self;
899+
900+
ty.visit_with(visitor)?;
901+
mutbl.visit_with(visitor)
870902
}
871903
}
872904

@@ -876,9 +908,45 @@ BraceStructTypeFoldableImpl! {
876908
}
877909
}
878910

879-
BraceStructTypeFoldableImpl! {
880-
impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
881-
inputs_and_output, c_variadic, unsafety, abi
911+
impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
912+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
913+
-> Result<Self, F::Error>
914+
{
915+
let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } = self;
916+
917+
let inputs_and_output = if folder.use_variances() {
918+
let inputs_and_output = self.inputs().iter().cloned()
919+
.map(|x| (x, false))
920+
.chain(iter::once((self.output(), true)))
921+
.map(|(a, is_output)| {
922+
if is_output {
923+
a.fold_with(folder)
924+
} else {
925+
folder.fold_with_variance(ty::Contravariant, &a)
926+
}
927+
}).collect::<Result<SmallVec<[_; 8]>, _>>()?;
928+
folder.tcx().intern_type_list(&inputs_and_output)
929+
} else {
930+
folder.fold_with_variance(ty::Invariant, inputs_and_output)?
931+
};
932+
933+
Ok(ty::FnSig {
934+
inputs_and_output,
935+
c_variadic: *c_variadic,
936+
unsafety: *unsafety,
937+
abi: *abi,
938+
})
939+
}
940+
941+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V)
942+
-> Result<(), V::Error>
943+
{
944+
let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } = self;
945+
946+
inputs_and_output.visit_with(visitor)?;
947+
c_variadic.visit_with(visitor)?;
948+
unsafety.visit_with(visitor)?;
949+
abi.visit_with(visitor)
882950
}
883951
}
884952

src/librustc/ty/subst.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,9 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
329329
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
330330
-> Result<Self, F::Error>
331331
{
332-
let params = self.iter().map(|k| k.fold_with(folder))
333-
.collect::<Result<SmallVec<[_; 8]>, _>>()?;
332+
let params = self.iter().map(|k| {
333+
folder.fold_with_variance(ty::Invariant, k)
334+
}).collect::<Result<SmallVec<[_; 8]>, _>>()?;
334335

335336
// If folding doesn't change the substs, it's faster to avoid
336337
// calling `mk_substs` and instead reuse the existing substs.
@@ -349,6 +350,27 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
349350
}
350351
}
351352

353+
pub fn fold_with_variances<'gcx, 'tcx, F: TypeFolder<'gcx, 'tcx>>(
354+
folder: &mut F,
355+
variances: &[ty::Variance],
356+
substs: SubstsRef<'tcx>)
357+
-> Result<SubstsRef<'tcx>, F::Error>
358+
{
359+
assert_eq!(substs.len(), variances.len());
360+
361+
let params = substs.iter().zip(variances.iter()).map(|(k, v)| {
362+
folder.fold_with_variance(*v, k)
363+
}).collect::<Result<SmallVec<[_; 8]>, _>>()?;
364+
365+
// If folding doesn't change the substs, it's faster to avoid
366+
// calling `mk_substs` and instead reuse the existing substs.
367+
if params[..] == substs[..] {
368+
Ok(substs)
369+
} else {
370+
Ok(folder.tcx().intern_substs(&params))
371+
}
372+
}
373+
352374
impl<'tcx> serialize::UseSpecializedDecodable for SubstsRef<'tcx> {}
353375

354376
///////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)