]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_middle/src/ty/fold.rs
Auto merge of #92130 - Kobzol:stable-hash-str, r=cjgillot
[rust.git] / compiler / rustc_middle / src / ty / fold.rs
index 31055c03a5d36c73e551ddbf76377ef6699f081d..f5be8b21e8acae5b7103553d4bec742fccfc66a3 100644 (file)
 ///
 /// 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>;
@@ -178,8 +199,8 @@ fn still_further_specializable(&self) -> bool {
     }
 }
 
-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> {
@@ -192,41 +213,102 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::Br
 /// 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> {
@@ -234,6 +316,49 @@ fn fold_mir_const(
     }
 }
 
+// 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
@@ -301,22 +426,19 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         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)
     }
 }
 
@@ -336,7 +458,7 @@ pub fn fold_regions<T>(
     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`.
@@ -484,7 +606,7 @@ fn tcx<'b>(&'b self) -> TyCtxt<'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);
@@ -492,16 +614,16 @@ fn fold_binder<T: TypeFoldable<'tcx>>(
     }
 
     #[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)
             }
         }
     }
@@ -542,19 +664,19 @@ fn tcx<'b>(&'b self) -> TyCtxt<'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_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) => {
@@ -562,10 +684,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
             }
             _ => {}
         }
-        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() {
@@ -576,28 +698,25 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self:
                         // 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) => {
@@ -605,7 +724,7 @@ fn fold_const(
             }
             _ => {}
         }
-        Ok(ct)
+        ct
     }
 }
 
@@ -638,7 +757,7 @@ pub fn replace_late_bound_regions<T, F>(
             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)
     }
@@ -664,7 +783,7 @@ pub fn replace_escaping_bound_vars<T, F, G, H>(
         } 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)
         }
     }
 
@@ -941,13 +1060,13 @@ struct Shifter<'tcx> {
     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
     }
@@ -955,36 +1074,36 @@ fn tcx<'b>(&'b self) -> TyCtxt<'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))
                 }
             }
 
@@ -992,18 +1111,13 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         }
     }
 
-    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)
@@ -1030,7 +1144,7 @@ pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T
 {
     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)]
@@ -1143,7 +1257,7 @@ struct HasTypeFlagsVisitor<'tcx> {
     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)
     }
@@ -1293,7 +1407,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ///
     /// 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 })
     }
 }
 
@@ -1306,22 +1420,19 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         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
         }
     }
 }
@@ -1343,7 +1454,7 @@ struct LateBoundRegionsCollector<'tcx> {
     just_constrained: bool,
 }
 
-impl LateBoundRegionsCollector<'tcx> {
+impl<'tcx> LateBoundRegionsCollector<'tcx> {
     fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self {
         LateBoundRegionsCollector {
             tcx,