From 6e3fa20b00d5b3713848aa162969d7a460bd194a Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 19 May 2021 13:34:54 +0200 Subject: [PATCH] Make `TypeFoldable` implementors short-circuit on error Co-authored-by: Alan Egerton --- compiler/rustc_data_structures/src/functor.rs | 70 ++++++- .../src/traits/structural_impls.rs | 10 +- compiler/rustc_macros/src/type_foldable.rs | 6 +- compiler/rustc_middle/src/macros.rs | 14 +- compiler/rustc_middle/src/mir/mod.rs | 10 +- .../rustc_middle/src/mir/type_foldable.rs | 175 +++++++++--------- compiler/rustc_middle/src/ty/fold.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 7 +- .../rustc_middle/src/ty/structural_impls.rs | 162 ++++++++-------- compiler/rustc_middle/src/ty/sty.rs | 12 ++ compiler/rustc_middle/src/ty/subst.rs | 33 ++-- 11 files changed, 299 insertions(+), 204 deletions(-) diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs index 5b83ae31247..1307c68ba0b 100644 --- a/compiler/rustc_data_structures/src/functor.rs +++ b/compiler/rustc_data_structures/src/functor.rs @@ -2,12 +2,16 @@ use rustc_index::vec::{Idx, IndexVec}; use std::mem; use std::ptr; -pub trait IdFunctor { +pub trait IdFunctor: Sized { type Inner; fn map_id(self, f: F) -> Self where F: FnMut(Self::Inner) -> Self::Inner; + + fn try_map_id(self, f: F) -> Result + where + F: FnMut(Self::Inner) -> Result; } impl IdFunctor for Box { @@ -31,6 +35,25 @@ impl IdFunctor for Box { raw.assume_init() } } + + #[inline] + fn try_map_id(self, mut f: F) -> Result + where + F: FnMut(Self::Inner) -> Result, + { + let raw = Box::into_raw(self); + Ok(unsafe { + // SAFETY: The raw pointer points to a valid value of type `T`. + let value = ptr::read(raw); + // SAFETY: Converts `Box` to `Box>` which is the + // inverse of `Box::assume_init()` and should be safe. + let mut raw: Box> = Box::from_raw(raw.cast()); + // SAFETY: Write the mapped value back into the `Box`. + ptr::write(raw.as_mut_ptr(), f(value)?); + // SAFETY: We just initialized `raw`. + raw.assume_init() + }) + } } impl IdFunctor for Vec { @@ -55,6 +78,35 @@ impl IdFunctor for Vec { } self } + + #[inline] + fn try_map_id(mut self, mut f: F) -> Result + where + F: FnMut(Self::Inner) -> Result, + { + // FIXME: We don't really care about panics here and leak + // far more than we should, but that should be fine for now. + let len = self.len(); + let mut error = Ok(()); + unsafe { + self.set_len(0); + let start = self.as_mut_ptr(); + for i in 0..len { + let p = start.add(i); + match f(ptr::read(p)) { + Ok(value) => ptr::write(p, value), + Err(err) => { + error = Err(err); + break; + } + } + } + // Even if we encountered an error, set the len back + // so we don't leak memory. + self.set_len(len); + } + error.map(|()| self) + } } impl IdFunctor for Box<[T]> { @@ -67,6 +119,14 @@ impl IdFunctor for Box<[T]> { { Vec::from(self).map_id(f).into() } + + #[inline] + fn try_map_id(self, f: F) -> Result + where + F: FnMut(Self::Inner) -> Result, + { + Vec::from(self).try_map_id(f).map(Into::into) + } } impl IdFunctor for IndexVec { @@ -79,4 +139,12 @@ impl IdFunctor for IndexVec { { IndexVec::from_raw(self.raw.map_id(f)) } + + #[inline] + fn try_map_id(self, f: F) -> Result + where + F: FnMut(Self::Inner) -> Result, + { + self.raw.try_map_id(f).map(IndexVec::from_raw) + } } diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index c4a2ecee096..1ce5f356910 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -60,13 +60,13 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { // TypeFoldable implementations. impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { - fn super_fold_with>(self, folder: &mut F) -> Self { - traits::Obligation { + fn super_fold_with>(self, folder: &mut F) -> Result { + Ok(traits::Obligation { cause: self.cause, recursion_depth: self.recursion_depth, - predicate: self.predicate.fold_with(folder), - param_env: self.param_env.fold_with(folder), - } + predicate: self.predicate.fold_with(folder)?, + param_env: self.param_env.fold_with(folder)?, + }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 082af087bf4..769f009b492 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -17,7 +17,7 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: vi.construct(|_, index| { let bind = &bindings[index]; quote! { - ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder) + ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)? } }) }); @@ -28,8 +28,8 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>( self, __folder: &mut __F - ) -> Self { - match self { #body_fold } + ) -> Result { + Ok(match self { #body_fold }) } fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>( diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index c0f2a76c19d..c0cf265b228 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -55,8 +55,8 @@ macro_rules! TrivialTypeFoldableImpls { fn super_fold_with>( self, _: &mut F - ) -> $ty { - self + ) -> ::std::result::Result<$ty, F::Error> { + Ok(self) } fn super_visit_with>( @@ -98,7 +98,7 @@ macro_rules! EnumTypeFoldableImpl { fn super_fold_with>( self, folder: &mut V, - ) -> Self { + ) -> ::std::result::Result { EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output()) } @@ -112,9 +112,9 @@ macro_rules! EnumTypeFoldableImpl { }; (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => { - match $this { + Ok(match $this { $($output)* - } + }) }; (@FoldVariants($this:expr, $folder:expr) @@ -126,7 +126,7 @@ macro_rules! EnumTypeFoldableImpl { output( $variant ( $($variant_arg),* ) => { $variant ( - $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),* + $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)?),* ) } $($output)* @@ -145,7 +145,7 @@ macro_rules! EnumTypeFoldableImpl { $variant { $($variant_arg: $crate::ty::fold::TypeFoldable::fold_with( $variant_arg, $folder - )),* } + )?),* } } $($output)* ) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4210e07d278..a05b8a1da8d 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2760,11 +2760,11 @@ impl UserTypeProjection { TrivialTypeFoldableAndLiftImpls! { ProjectionKind, } impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { - fn super_fold_with>(self, folder: &mut F) -> Self { - UserTypeProjection { - base: self.base.fold_with(folder), - projs: self.projs.fold_with(folder), - } + fn super_fold_with>(self, folder: &mut F) -> Result { + Ok(UserTypeProjection { + base: self.base.fold_with(folder)?, + projs: self.projs.fold_with(folder)?, + }) } fn super_visit_with>( diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index b7201f7acf3..df7c6d9cf66 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -16,37 +16,39 @@ TrivialTypeFoldableAndLiftImpls! { } impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { use crate::mir::TerminatorKind::*; let kind = match self.kind { Goto { target } => Goto { target }, SwitchInt { discr, switch_ty, targets } => SwitchInt { - discr: discr.fold_with(folder), - switch_ty: switch_ty.fold_with(folder), + discr: discr.fold_with(folder)?, + switch_ty: switch_ty.fold_with(folder)?, targets, }, Drop { place, target, unwind } => { - Drop { place: place.fold_with(folder), target, unwind } + Drop { place: place.fold_with(folder)?, target, unwind } } DropAndReplace { place, value, target, unwind } => DropAndReplace { - place: place.fold_with(folder), - value: value.fold_with(folder), + place: place.fold_with(folder)?, + value: value.fold_with(folder)?, target, unwind, }, Yield { value, resume, resume_arg, drop } => Yield { - value: value.fold_with(folder), + value: value.fold_with(folder)?, resume, - resume_arg: resume_arg.fold_with(folder), + resume_arg: resume_arg.fold_with(folder)?, drop, }, Call { func, args, destination, cleanup, from_hir_call, fn_span } => { - let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest)); + let dest = destination + .map(|(loc, dest)| (loc.fold_with(folder).map(|loc| (loc, dest)))) + .transpose()?; Call { - func: func.fold_with(folder), - args: args.fold_with(folder), + func: func.fold_with(folder)?, + args: args.fold_with(folder)?, destination: dest, cleanup, from_hir_call, @@ -57,15 +59,15 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { use AssertKind::*; let msg = match msg { BoundsCheck { len, index } => { - BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) } + BoundsCheck { len: len.fold_with(folder)?, index: index.fold_with(folder)? } } - Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)), - OverflowNeg(op) => OverflowNeg(op.fold_with(folder)), - DivisionByZero(op) => DivisionByZero(op.fold_with(folder)), - RemainderByZero(op) => RemainderByZero(op.fold_with(folder)), + Overflow(op, l, r) => Overflow(op, l.fold_with(folder)?, r.fold_with(folder)?), + OverflowNeg(op) => OverflowNeg(op.fold_with(folder)?), + DivisionByZero(op) => DivisionByZero(op.fold_with(folder)?), + RemainderByZero(op) => RemainderByZero(op.fold_with(folder)?), ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg, }; - Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup } + Assert { cond: cond.fold_with(folder)?, expected, msg, target, cleanup } } GeneratorDrop => GeneratorDrop, Resume => Resume, @@ -78,13 +80,13 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, InlineAsm { template, operands, options, line_spans, destination } => InlineAsm { template, - operands: operands.fold_with(folder), + operands: operands.fold_with(folder)?, options, line_spans, destination, }, }; - Terminator { source_info: self.source_info, kind } + Ok(Terminator { source_info: self.source_info, kind }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -140,8 +142,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { - fn super_fold_with>(self, _: &mut F) -> Self { - self + fn super_fold_with>(self, _: &mut F) -> Result { + Ok(self) } fn super_visit_with>(&self, _: &mut V) -> ControlFlow { @@ -150,8 +152,11 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { } impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { - Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } + fn super_fold_with>(self, folder: &mut F) -> Result { + Ok(Place { + local: self.local.fold_with(folder)?, + projection: self.projection.fold_with(folder)?, + }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -161,7 +166,7 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v)) } @@ -171,47 +176,49 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { use crate::mir::Rvalue::*; - match self { - Use(op) => Use(op.fold_with(folder)), - Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)), - ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)), - Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)), - AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)), - Len(place) => Len(place.fold_with(folder)), - Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), + Ok(match self { + Use(op) => Use(op.fold_with(folder)?), + Repeat(op, len) => Repeat(op.fold_with(folder)?, len.fold_with(folder)?), + ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)?), + Ref(region, bk, place) => Ref(region.fold_with(folder)?, bk, place.fold_with(folder)?), + AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)?), + Len(place) => Len(place.fold_with(folder)?), + Cast(kind, op, ty) => Cast(kind, op.fold_with(folder)?, ty.fold_with(folder)?), BinaryOp(op, box (rhs, lhs)) => { - BinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder)))) + BinaryOp(op, Box::new((rhs.fold_with(folder)?, lhs.fold_with(folder)?))) } CheckedBinaryOp(op, box (rhs, lhs)) => { - CheckedBinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder)))) + CheckedBinaryOp(op, Box::new((rhs.fold_with(folder)?, lhs.fold_with(folder)?))) } - UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)), - Discriminant(place) => Discriminant(place.fold_with(folder)), - NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), + UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)?), + Discriminant(place) => Discriminant(place.fold_with(folder)?), + NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)?), Aggregate(kind, fields) => { - let kind = kind.map_id(|kind| match kind { - AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), - AggregateKind::Tuple => AggregateKind::Tuple, - AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( - def, - v, - substs.fold_with(folder), - user_ty.fold_with(folder), - n, - ), - AggregateKind::Closure(id, substs) => { - AggregateKind::Closure(id, substs.fold_with(folder)) - } - AggregateKind::Generator(id, substs, movablity) => { - AggregateKind::Generator(id, substs.fold_with(folder), movablity) - } - }); - Aggregate(kind, fields.fold_with(folder)) + let kind = kind.try_map_id(|kind| { + Ok(match kind { + AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)?), + AggregateKind::Tuple => AggregateKind::Tuple, + AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( + def, + v, + substs.fold_with(folder)?, + user_ty.fold_with(folder)?, + n, + ), + AggregateKind::Closure(id, substs) => { + AggregateKind::Closure(id, substs.fold_with(folder)?) + } + AggregateKind::Generator(id, substs, movablity) => { + AggregateKind::Generator(id, substs.fold_with(folder)?, movablity) + } + }) + })?; + Aggregate(kind, fields.fold_with(folder)?) } - ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)), - } + ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder)?, ty.fold_with(folder)?), + }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -265,12 +272,12 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { - match self { - Operand::Copy(place) => Operand::Copy(place.fold_with(folder)), - Operand::Move(place) => Operand::Move(place.fold_with(folder)), - Operand::Constant(c) => Operand::Constant(c.fold_with(folder)), - } + fn super_fold_with>(self, folder: &mut F) -> Result { + Ok(match self { + Operand::Copy(place) => Operand::Copy(place.fold_with(folder)?), + Operand::Move(place) => Operand::Move(place.fold_with(folder)?), + Operand::Constant(c) => Operand::Constant(c.fold_with(folder)?), + }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -282,19 +289,19 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { use crate::mir::ProjectionElem::*; - match self { + Ok(match self { Deref => Deref, - Field(f, ty) => Field(f, ty.fold_with(folder)), - Index(v) => Index(v.fold_with(folder)), + Field(f, ty) => Field(f, ty.fold_with(folder)?), + Index(v) => Index(v.fold_with(folder)?), Downcast(symbol, variantidx) => Downcast(symbol, variantidx), ConstantIndex { offset, min_length, from_end } => { ConstantIndex { offset, min_length, from_end } } Subslice { from, to, from_end } => Subslice { from, to, from_end }, - } + }) } fn super_visit_with>( @@ -312,8 +319,8 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for Field { - fn super_fold_with>(self, _: &mut F) -> Self { - self + fn super_fold_with>(self, _: &mut F) -> Result { + Ok(self) } fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE @@ -321,8 +328,8 @@ impl<'tcx> TypeFoldable<'tcx> for Field { } impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { - fn super_fold_with>(self, _: &mut F) -> Self { - self + fn super_fold_with>(self, _: &mut F) -> Result { + Ok(self) } fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE @@ -330,8 +337,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { } impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix { - fn super_fold_with>(self, _: &mut F) -> Self { - self + fn super_fold_with>(self, _: &mut F) -> Result { + Ok(self) } fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE @@ -339,12 +346,12 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix { } impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { - Constant { + fn super_fold_with>(self, folder: &mut F) -> Result { + Ok(Constant { span: self.span, - user_ty: self.user_ty.fold_with(folder), - literal: self.literal.fold_with(folder), - } + user_ty: self.user_ty.fold_with(folder)?, + literal: self.literal.fold_with(folder)?, + }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.literal.visit_with(visitor)?; @@ -354,14 +361,14 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { #[inline(always)] - fn fold_with>(self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Result { folder.fold_mir_const(self) } - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { match self { - ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)), - ConstantKind::Val(v, t) => ConstantKind::Val(v, t.fold_with(folder)), + ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.fold_with(folder)?)), + ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.fold_with(folder)?)), } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a306656984f..3b77b5a9d46 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -179,8 +179,8 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } impl TypeFoldable<'tcx> for hir::Constness { - fn super_fold_with>(self, _: &mut F) -> Self { - self + fn super_fold_with>(self, _: &mut F) -> Result { + Ok(self) } fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 673733faa76..2d692670372 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1260,8 +1260,11 @@ impl<'a, 'tcx> HashStable> for ParamEnv<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { - ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) + fn super_fold_with>( + self, + folder: &mut F, + ) -> Result { + Ok(ParamEnv::new(self.caller_bounds().fold_with(folder)?, self.reveal().fold_with(folder)?)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 0f8e80806e3..a2612df5a44 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -669,8 +669,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { /// AdtDefs are basically the same as a DefId. impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { - fn super_fold_with>(self, _folder: &mut F) -> Self { - self + fn super_fold_with>(self, _folder: &mut F) -> Result { + Ok(self) } fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { @@ -679,8 +679,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { } impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { - fn super_fold_with>(self, folder: &mut F) -> (T, U) { - (self.0.fold_with(folder), self.1.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Result<(T, U), F::Error> { + Ok((self.0.fold_with(folder)?, self.1.fold_with(folder)?)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -692,8 +692,8 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (A, B, C) { - fn super_fold_with>(self, folder: &mut F) -> (A, B, C) { - (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Result<(A, B, C), F::Error> { + Ok((self.0.fold_with(folder)?, self.1.fold_with(folder)?, self.2.fold_with(folder)?)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -718,9 +718,9 @@ EnumTypeFoldableImpl! { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { // FIXME: Reuse the `Rc` here. - Rc::new((*self).clone().fold_with(folder)) + Ok(Rc::new((*self).clone().fold_with(folder)?)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -729,9 +729,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { // FIXME: Reuse the `Arc` here. - Arc::new((*self).clone().fold_with(folder)) + Ok(Arc::new((*self).clone().fold_with(folder)?)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -740,8 +740,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { - fn super_fold_with>(self, folder: &mut F) -> Self { - self.map_id(|value| value.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Result { + self.try_map_id(|value| value.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -750,8 +750,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { - fn super_fold_with>(self, folder: &mut F) -> Self { - self.map_id(|t| t.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Result { + self.try_map_id(|t| t.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -760,8 +760,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { - fn super_fold_with>(self, folder: &mut F) -> Self { - self.map_id(|t| t.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Result { + self.try_map_id(|t| t.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -770,11 +770,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> { - fn super_fold_with>(self, folder: &mut F) -> Self { - self.map_bound(|ty| ty.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Result { + self.try_map_bound(|ty| ty.fold_with(folder)) } - fn fold_with>(self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Result { folder.fold_binder(self) } @@ -788,7 +788,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> { } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List>> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v)) } @@ -798,7 +798,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)) } @@ -808,7 +808,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v)) } @@ -818,24 +818,24 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List { } impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { use crate::ty::InstanceDef::*; - Self { - substs: self.substs.fold_with(folder), + Ok(Self { + substs: self.substs.fold_with(folder)?, def: match self.def { - Item(def) => Item(def.fold_with(folder)), - VtableShim(did) => VtableShim(did.fold_with(folder)), - ReifyShim(did) => ReifyShim(did.fold_with(folder)), - Intrinsic(did) => Intrinsic(did.fold_with(folder)), - FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)), - Virtual(did, i) => Virtual(did.fold_with(folder), i), + Item(def) => Item(def.fold_with(folder)?), + VtableShim(did) => VtableShim(did.fold_with(folder)?), + ReifyShim(did) => ReifyShim(did.fold_with(folder)?), + Intrinsic(did) => Intrinsic(did.fold_with(folder)?), + FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder)?, ty.fold_with(folder)?), + Virtual(did, i) => Virtual(did.fold_with(folder)?, i), ClosureOnceShim { call_once, track_caller } => { - ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller } + ClosureOnceShim { call_once: call_once.fold_with(folder)?, track_caller } } - DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)), - CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)), + DropGlue(did, ty) => DropGlue(did.fold_with(folder)?, ty.fold_with(folder)?), + CloneShim(did, ty) => CloneShim(did.fold_with(folder)?, ty.fold_with(folder)?), }, - } + }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -860,8 +860,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { - Self { instance: self.instance.fold_with(folder), promoted: self.promoted } + fn super_fold_with>(self, folder: &mut F) -> Result { + Ok(Self { instance: self.instance.fold_with(folder)?, promoted: self.promoted }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -870,26 +870,26 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { let kind = match *self.kind() { - ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), - ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), - ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), - ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)), + ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)?), + ty::Array(typ, sz) => ty::Array(typ.fold_with(folder)?, sz.fold_with(folder)?), + ty::Slice(typ) => ty::Slice(typ.fold_with(folder)?), + ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)?), ty::Dynamic(trait_ty, region) => { - ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)) + ty::Dynamic(trait_ty.fold_with(folder)?, region.fold_with(folder)?) } - ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), - ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)), - ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)), - ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), + ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)?), + ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)?), + ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)?), + ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder)?, ty.fold_with(folder)?, mutbl), ty::Generator(did, substs, movability) => { - ty::Generator(did, substs.fold_with(folder), movability) + ty::Generator(did, substs.fold_with(folder)?, movability) } - ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)), - ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)), - ty::Projection(data) => ty::Projection(data.fold_with(folder)), - ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), + ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)?), + ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)?), + ty::Projection(data) => ty::Projection(data.fold_with(folder)?), + ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)?), ty::Bool | ty::Char @@ -903,13 +903,13 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { | ty::Bound(..) | ty::Placeholder(..) | ty::Never - | ty::Foreign(..) => return self, + | ty::Foreign(..) => return Ok(self), }; - if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) } + Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }) } - fn fold_with>(self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Result { folder.fold_ty(self) } @@ -961,11 +961,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { - fn super_fold_with>(self, _folder: &mut F) -> Self { - self + fn super_fold_with>(self, _folder: &mut F) -> Result { + Ok(self) } - fn fold_with>(self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Result { folder.fold_region(self) } @@ -979,13 +979,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { - fn fold_with>(self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Result { folder.fold_predicate(self) } - fn super_fold_with>(self, folder: &mut F) -> Self { - let new = self.inner.kind.fold_with(folder); - folder.tcx().reuse_or_mk_predicate(self, new) + fn super_fold_with>(self, folder: &mut F) -> Result { + let new = self.inner.kind.fold_with(folder)?; + Ok(folder.tcx().reuse_or_mk_predicate(self, new)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -1006,7 +1006,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v)) } @@ -1016,8 +1016,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec { - fn super_fold_with>(self, folder: &mut F) -> Self { - self.map_id(|x| x.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Result { + self.try_map_id(|x| x.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -1026,17 +1026,17 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { - let ty = self.ty.fold_with(folder); - let val = self.val.fold_with(folder); + fn super_fold_with>(self, folder: &mut F) -> Result { + let ty = self.ty.fold_with(folder)?; + let val = self.val.fold_with(folder)?; if ty != self.ty || val != self.val { - folder.tcx().mk_const(ty::Const { ty, val }) + Ok(folder.tcx().mk_const(ty::Const { ty, val })) } else { - self + Ok(self) } } - fn fold_with>(self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Result { folder.fold_const(self) } @@ -1051,16 +1051,16 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { - match self { - ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), - ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), - ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)), + fn super_fold_with>(self, folder: &mut F) -> Result { + Ok(match self { + ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)?), + ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)?), + ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)?), ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) | ty::ConstKind::Error(_) => self, - } + }) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { @@ -1077,8 +1077,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { - fn super_fold_with>(self, _folder: &mut F) -> Self { - self + fn super_fold_with>(self, _folder: &mut F) -> Result { + Ok(self) } fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { @@ -1090,7 +1090,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> { fn super_fold_with>(self, folder: &mut F) -> Self { ty::Unevaluated { def: self.def, - substs_: Some(self.substs(folder.tcx()).fold_with(folder)), + substs_: Some(self.substs(folder.tcx()).fold_with(folder)?), promoted: self.promoted, } } @@ -1115,7 +1115,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> { fn super_fold_with>(self, folder: &mut F) -> Self { ty::Unevaluated { def: self.def, - substs_: Some(self.substs(folder.tcx()).fold_with(folder)), + substs_: Some(self.substs(folder.tcx()).fold_with(folder)?), promoted: self.promoted, } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c2b32cd06ea..fcbf15b3bca 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1101,6 +1101,18 @@ impl<'tcx, T> Binder<'tcx, T> { Binder(value, self.1) } + pub fn try_map_bound, E>(self, f: F) -> Result, E> + where + F: FnOnce(T) -> Result, + { + let value = f(self.0)?; + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(self.1); + value.visit_with(&mut validator); + } + Ok(Binder(value, self.1)) + } + /// Wraps a `value` in a binder, using the same bound variables as the /// current `Binder`. This should not be used if the new value *changes* /// the bound variables. Note: the (old or new) value itself does not diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 73a8e18949d..67cf21a9556 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -153,11 +153,11 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { } impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), - GenericArgKind::Type(ty) => ty.fold_with(folder).into(), - GenericArgKind::Const(ct) => ct.fold_with(folder).into(), + GenericArgKind::Lifetime(lt) => lt.fold_with(folder).map(Into::into), + GenericArgKind::Type(ty) => ty.fold_with(folder).map(Into::into), + GenericArgKind::Const(ct) => ct.fold_with(folder).map(Into::into), } } @@ -372,7 +372,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Result { // This code is hot enough that it's worth specializing for the most // common length lists, to avoid the overhead of `SmallVec` creation. // The match arms are in order of frequency. The 1, 2, and 0 cases are @@ -381,22 +381,27 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { // calling `intern_substs`. match self.len() { 1 => { - let param0 = self[0].fold_with(folder); - if param0 == self[0] { self } else { folder.tcx().intern_substs(&[param0]) } + let param0 = self[0].fold_with(folder)?; + if param0 == self[0] { Ok(self) } else { Ok(folder.tcx().intern_substs(&[param0])) } } 2 => { - let param0 = self[0].fold_with(folder); - let param1 = self[1].fold_with(folder); + let param0 = self[0].fold_with(folder)?; + let param1 = self[1].fold_with(folder)?; if param0 == self[0] && param1 == self[1] { - self + Ok(self) } else { - folder.tcx().intern_substs(&[param0, param1]) + Ok(folder.tcx().intern_substs(&[param0, param1])) } } - 0 => self, + 0 => Ok(self), _ => { - let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect(); - if params[..] == self[..] { self } else { folder.tcx().intern_substs(¶ms) } + let params: SmallVec<[_; 8]> = + self.iter().map(|k| k.fold_with(folder)).collect::>()?; + if params[..] == self[..] { + Ok(self) + } else { + Ok(folder.tcx().intern_substs(¶ms)) + } } } }