Skip to content

Commit 60dd5f7

Browse files
committed
add variance support to TypeFoldable
1 parent e8601fe commit 60dd5f7

File tree

4 files changed

+134
-14
lines changed

4 files changed

+134
-14
lines changed

src/librustc/ty/fold.rs

+30
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::Substs;
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: &'tcx Substs<'tcx>)
180+
-> Result<&'tcx Substs<'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

+79-11
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
@@ -764,16 +766,24 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
764766
ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)?),
765767
ty::Array(typ, sz) => ty::Array(typ.fold_with(folder)?, sz.fold_with(folder)?),
766768
ty::Slice(typ) => ty::Slice(typ.fold_with(folder)?),
767-
ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)?),
768-
ty::Dynamic(ref trait_ty, ref region) =>
769-
ty::Dynamic(trait_ty.fold_with(folder)?, region.fold_with(folder)?),
769+
ty::Adt(tid, substs) => {
770+
ty::Adt(tid, folder.fold_item_substs(tid.did, substs)?)
771+
}
772+
ty::Dynamic(ref trait_ty, ref region) => {
773+
let principal = trait_ty.fold_with(folder)?;
774+
let region_bound = folder.fold_with_variance(ty::Contravariant, region)?;
775+
ty::Dynamic(principal, region_bound)
776+
}
770777
ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)?),
771778
ty::FnDef(def_id, substs) => {
772-
ty::FnDef(def_id, substs.fold_with(folder)?)
779+
ty::FnDef(def_id, folder.fold_item_substs(def_id, substs)?)
773780
}
774781
ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)?),
775782
ty::Ref(ref r, ty, mutbl) => {
776-
ty::Ref(r.fold_with(folder)?, ty.fold_with(folder)?, mutbl)
783+
let r = folder.fold_with_variance(ty::Contravariant, r)?;
784+
// Fold the type as a TypeAndMut to get the correct variance.
785+
let mt = ty::TypeAndMut { ty, mutbl }.fold_with(folder)?;
786+
ty::Ref(r, mt.ty, mt.mutbl)
777787
}
778788
ty::Generator(did, substs, movability) => {
779789
ty::Generator(
@@ -858,9 +868,31 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
858868
}
859869
}
860870

861-
BraceStructTypeFoldableImpl! {
862-
impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
863-
ty, mutbl
871+
872+
873+
impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
874+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
875+
-> Result<Self, F::Error>
876+
{
877+
let ty::TypeAndMut { ty, mutbl } = self;
878+
let variance = match mutbl {
879+
hir::Mutability::MutImmutable => ty::Covariant,
880+
hir::Mutability::MutMutable => ty::Invariant,
881+
};
882+
883+
Ok(ty::TypeAndMut {
884+
ty: folder.fold_with_variance(variance, ty)?,
885+
mutbl: mutbl.fold_with(folder)?,
886+
})
887+
}
888+
889+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V)
890+
-> Result<(), V::Error>
891+
{
892+
let ty::TypeAndMut { ty, mutbl } = self;
893+
894+
ty.visit_with(visitor)?;
895+
mutbl.visit_with(visitor)
864896
}
865897
}
866898

@@ -870,9 +902,45 @@ BraceStructTypeFoldableImpl! {
870902
}
871903
}
872904

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

src/librustc/ty/subst.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,9 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
327327
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
328328
-> Result<Self, F::Error>
329329
{
330-
let params = self.iter().map(|k| k.fold_with(folder))
331-
.collect::<Result<SmallVec<[_; 8]>, _>>()?;
330+
let params = self.iter().map(|k| {
331+
folder.fold_with_variance(ty::Invariant, k)
332+
}).collect::<Result<SmallVec<[_; 8]>, _>>()?;
332333

333334
// If folding doesn't change the substs, it's faster to avoid
334335
// calling `mk_substs` and instead reuse the existing substs.
@@ -347,6 +348,27 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
347348
}
348349
}
349350

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

352374
///////////////////////////////////////////////////////////////////////////

src/llvm-project

Submodule llvm-project updated 35 files

0 commit comments

Comments
 (0)