///
/// To implement this conveniently, use the derive macro located in `rustc_macros`.
pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- self.super_fold_with(folder)
+ /// Consumers may find this more convenient to use with infallible folders than
+ /// [`try_super_fold_with`][`TypeFoldable::try_super_fold_with`], to which the
+ /// provided default definition delegates. Implementors **should not** override
+ /// this provided default definition, to ensure that the two methods are coherent
+ /// (provide a definition of `try_super_fold_with` instead).
+ fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+ self.try_super_fold_with(folder).into_ok()
+ }
+ /// Consumers may find this more convenient to use with infallible folders than
+ /// [`try_fold_with`][`TypeFoldable::try_fold_with`], to which the provided
+ /// default definition delegates. Implementors **should not** override this
+ /// provided default definition, to ensure that the two methods are coherent
+ /// (provide a definition of `try_fold_with` instead).
+ fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+ self.try_fold_with(folder).into_ok()
+ }
+
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error>;
+
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_super_fold_with(folder)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
}
}
-impl TypeFoldable<'tcx> for hir::Constness {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
+ fn try_super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
/// default implementation that does an "identity" fold. Within each
/// identity fold, it should invoke `foo.fold_with(self)` to fold each
/// sub-item.
+///
+/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
+/// associated type is something other than the default, never),
+/// [`FallibleTypeFolder`] should be implemented manually; otherwise,
+/// a blanket implementation of [`FallibleTypeFolder`] will defer to
+/// the infallible methods of this trait to ensure that the two APIs
+/// are coherent.
pub trait TypeFolder<'tcx>: Sized {
type Error = !;
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
- fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
where
T: TypeFoldable<'tcx>,
+ Self: TypeFolder<'tcx, Error = !>,
{
t.super_fold_with(self)
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
t.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
r.super_fold_with(self)
}
- fn fold_const(
+ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
+ c.super_fold_with(self)
+ }
+
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
+ p.super_fold_with(self)
+ }
+
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
+ bug!("most type folders should not be folding MIR datastructures: {:?}", c)
+ }
+}
+
+/// The `FallibleTypeFolder` trait defines the actual *folding*. There is a
+/// method defined for every foldable type. Each of these has a
+/// default implementation that does an "identity" fold. Within each
+/// identity fold, it should invoke `foo.try_fold_with(self)` to fold each
+/// sub-item.
+///
+/// A blanket implementation of this trait (that defers to the relevant
+/// method of [`TypeFolder`]) is provided for all infallible folders in
+/// order to ensure the two APIs are coherent.
+pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ r.try_super_fold_with(self)
+ }
+
+ fn try_fold_const(
&mut self,
c: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
- c.super_fold_with(self)
+ c.try_super_fold_with(self)
}
- fn fold_predicate(
+ fn try_fold_predicate(
&mut self,
p: ty::Predicate<'tcx>,
) -> Result<ty::Predicate<'tcx>, Self::Error> {
- p.super_fold_with(self)
+ p.try_super_fold_with(self)
}
- fn fold_mir_const(
+ fn try_fold_mir_const(
&mut self,
c: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
}
}
+// Blanket implementation of fallible trait for infallible folders
+// delegates to infallible methods to prevent incoherence
+impl<'tcx, F> FallibleTypeFolder<'tcx> for F
+where
+ F: TypeFolder<'tcx, Error = !>,
+{
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ Ok(self.fold_binder(t))
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ Ok(self.fold_ty(t))
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ Ok(self.fold_region(r))
+ }
+
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ Ok(self.fold_const(c))
+ }
+
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ Ok(self.fold_predicate(p))
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ Ok(self.fold_mir_const(c))
+ }
+}
+
pub trait TypeVisitor<'tcx>: Sized {
type BreakTy = !;
/// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
- let t = ty.super_fold_with(self)?;
- Ok((self.ty_op)(t))
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ let t = ty.super_fold_with(self);
+ (self.ty_op)(t)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
- let r = r.super_fold_with(self)?;
- Ok((self.lt_op)(r))
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ let r = r.super_fold_with(self);
+ (self.lt_op)(r)
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
- let ct = ct.super_fold_with(self)?;
- Ok((self.ct_op)(ct))
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ let ct = ct.super_fold_with(self);
+ (self.ct_op)(ct)
}
}
where
T: TypeFoldable<'tcx>,
{
- value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)).into_ok()
+ value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
}
/// Invoke `callback` on every region appearing free in `value`.
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
}
#[instrument(skip(self), level = "debug")]
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
debug!(?self.current_index, "skipped bound region");
*self.skipped_regions = true;
- Ok(r)
+ r
}
_ => {
debug!(?self.current_index, "folding free region");
- Ok((self.fold_region_fn)(r, self.current_index))
+ (self.fold_region_fn)(r, self.current_index)
}
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
if let Some(fld_t) = self.fld_t.as_mut() {
let ty = fld_t(bound_ty);
- return Ok(ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32()));
+ return ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32());
}
}
_ if t.has_vars_bound_at_or_above(self.current_index) => {
}
_ => {}
}
- Ok(t)
+ t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
if let Some(fld_r) = self.fld_r.as_mut() {
// debruijn index. Then we adjust it to the
// correct depth.
assert_eq!(debruijn1, ty::INNERMOST);
- Ok(self.tcx.mk_region(ty::ReLateBound(debruijn, br)))
+ self.tcx.mk_region(ty::ReLateBound(debruijn, br))
} else {
- Ok(region)
+ region
};
}
}
_ => {}
}
- Ok(r)
+ r
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match *ct {
ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
if debruijn == self.current_index =>
{
if let Some(fld_c) = self.fld_c.as_mut() {
let ct = fld_c(bound_const, ty);
- return Ok(ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32()));
+ return ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32());
}
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => {
}
_ => {}
}
- Ok(ct)
+ ct
}
}
value
} else {
let mut replacer = BoundVarReplacer::new(self, Some(&mut real_fld_r), None, None);
- value.fold_with(&mut replacer).into_ok()
+ value.fold_with(&mut replacer)
};
(value, region_map)
}
} else {
let mut replacer =
BoundVarReplacer::new(self, Some(&mut fld_r), Some(&mut fld_t), Some(&mut fld_c));
- value.fold_with(&mut replacer).into_ok()
+ value.fold_with(&mut replacer)
}
}
amount: u32,
}
-impl Shifter<'tcx> {
+impl<'tcx> Shifter<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self {
Shifter { tcx, current_index: ty::INNERMOST, amount }
}
}
-impl TypeFolder<'tcx> for Shifter<'tcx> {
+impl<'tcx> TypeFolder<'tcx> for Shifter<'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ ) -> ty::Binder<'tcx, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(debruijn, br) => {
if self.amount == 0 || debruijn < self.current_index {
- Ok(r)
+ r
} else {
let debruijn = debruijn.shifted_in(self.amount);
let shifted = ty::ReLateBound(debruijn, br);
- Ok(self.tcx.mk_region(shifted))
+ self.tcx.mk_region(shifted)
}
}
- _ => Ok(r),
+ _ => r,
}
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match *ty.kind() {
ty::Bound(debruijn, bound_ty) => {
if self.amount == 0 || debruijn < self.current_index {
- Ok(ty)
+ ty
} else {
let debruijn = debruijn.shifted_in(self.amount);
- Ok(self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)))
+ self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
}
}
}
}
- fn fold_const(
- &mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct {
if self.amount == 0 || debruijn < self.current_index {
- Ok(ct)
+ ct
} else {
let debruijn = debruijn.shifted_in(self.amount);
- Ok(self
- .tcx
- .mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }))
+ self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
}
} else {
ct.super_fold_with(self)
{
debug!("shift_vars(value={:?}, amount={})", value, amount);
- value.fold_with(&mut Shifter::new(tcx, amount)).into_ok()
+ value.fold_with(&mut Shifter::new(tcx, amount))
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
flags: ty::TypeFlags,
}
-impl std::fmt::Debug for HasTypeFlagsVisitor<'tcx> {
+impl<'tcx> std::fmt::Debug for HasTypeFlagsVisitor<'tcx> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.flags.fmt(fmt)
}
///
/// FIXME(@lcnr): explain this function a bit more
pub fn expose_default_const_substs<T: TypeFoldable<'tcx>>(self, v: T) -> T {
- v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self }).into_ok()
+ v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self })
}
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
ty.super_fold_with(self)
} else {
- Ok(ty)
+ ty
}
}
- fn fold_predicate(
- &mut self,
- pred: ty::Predicate<'tcx>,
- ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
pred.super_fold_with(self)
} else {
- Ok(pred)
+ pred
}
}
}
just_constrained: bool,
}
-impl LateBoundRegionsCollector<'tcx> {
+impl<'tcx> LateBoundRegionsCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self {
LateBoundRegionsCollector {
tcx,