Auto merge of #91230 - eggyal:fallible-type-fold, r=jackh726

Make `TypeFolder::fold_*` return `Result`

Implements rust-lang/compiler-team#432.

Initially this is just a rebase of `@LeSeulArtichaut's` work in #85469 (abandoned; see https://github.com/rust-lang/rust/pull/85485#issuecomment-908781112).  At that time, it caused a regression in performance that required some further exploration... with this rebased PR bors can hopefully report some perf analysis from which we can investigate further (if the regression is indeed still present).

r? `@jackh726` cc `@nikomatsakis`
This commit is contained in:
bors 2021-11-28 13:04:27 +00:00
commit e6d2de9483
45 changed files with 908 additions and 794 deletions

View File

@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust.
#![feature(trusted_len)]
#![feature(trusted_step)]
#![feature(try_blocks)]
#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]

View File

@ -95,7 +95,8 @@ pub fn equal_up_to_regions(
// Leave consts and types unchanged.
ct_op: |ct| ct,
ty_op: |ty| ty,
}),
})
.into_ok(),
)
};
tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())

View File

@ -1,35 +1,42 @@
use rustc_index::vec::{Idx, IndexVec};
use std::mem;
use std::ptr;
pub trait IdFunctor {
pub trait IdFunctor: Sized {
type Inner;
fn map_id<F>(self, f: F) -> Self
where
F: FnMut(Self::Inner) -> Self::Inner;
}
impl<T> IdFunctor for Box<T> {
type Inner = T;
#[inline]
fn map_id<F>(self, mut f: F) -> Self
where
F: FnMut(Self::Inner) -> Self::Inner,
{
self.try_map_id::<_, !>(|value| Ok(f(value))).into_ok()
}
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
}
impl<T> IdFunctor for Box<T> {
type Inner = T;
#[inline]
fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
where
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
let raw = Box::into_raw(self);
unsafe {
Ok(unsafe {
// SAFETY: The raw pointer points to a valid value of type `T`.
let value = ptr::read(raw);
let value = raw.read();
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
// inverse of `Box::assume_init()` and should be safe.
let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
// SAFETY: Write the mapped value back into the `Box`.
raw.write(f(value));
raw.write(f(value)?);
// SAFETY: We just initialized `raw`.
raw.assume_init()
}
})
}
}
@ -37,9 +44,9 @@ impl<T> IdFunctor for Vec<T> {
type Inner = T;
#[inline]
fn map_id<F>(mut self, mut f: F) -> Self
fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
where
F: FnMut(Self::Inner) -> Self::Inner,
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
// FIXME: We don't really care about panics here and leak
// far more than we should, but that should be fine for now.
@ -49,11 +56,26 @@ impl<T> IdFunctor for Vec<T> {
let start = self.as_mut_ptr();
for i in 0..len {
let p = start.add(i);
ptr::write(p, f(ptr::read(p)));
match f(p.read()) {
Ok(val) => p.write(val),
Err(err) => {
// drop all other elements in self
// (current element was "moved" into the call to f)
for j in (0..i).chain(i + 1..len) {
start.add(j).drop_in_place();
}
// returning will drop self, releasing the allocation
// (len is 0 so elements will not be re-dropped)
return Err(err);
}
}
}
// Even if we encountered an error, set the len back
// so we don't leak memory.
self.set_len(len);
}
self
Ok(self)
}
}
@ -61,11 +83,11 @@ impl<T> IdFunctor for Box<[T]> {
type Inner = T;
#[inline]
fn map_id<F>(self, f: F) -> Self
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
F: FnMut(Self::Inner) -> Self::Inner,
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
Vec::from(self).map_id(f).into()
Vec::from(self).try_map_id(f).map(Into::into)
}
}
@ -73,10 +95,10 @@ impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
type Inner = T;
#[inline]
fn map_id<F>(self, f: F) -> Self
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
F: FnMut(Self::Inner) -> Self::Inner,
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
IndexVec::from_raw(self.raw.map_id(f))
self.raw.try_map_id(f).map(IndexVec::from_raw)
}
}

View File

@ -25,6 +25,7 @@
#![feature(once_cell)]
#![feature(test)]
#![feature(thread_id_value)]
#![feature(unwrap_infallible)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]

View File

@ -278,7 +278,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
self.tcx
}
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
where
T: TypeFoldable<'tcx>,
{
@ -288,13 +288,13 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
t
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(index, ..) => {
if index >= self.binder_index {
bug!("escaping late-bound region during canonicalization");
} else {
r
Ok(r)
}
}
@ -311,7 +311,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
vid, r
);
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
self.canonicalize_region_mode.canonicalize_free_region(self, r)
Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r))
}
ty::ReStatic
@ -319,11 +319,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
| ty::ReFree(_)
| ty::ReEmpty(_)
| ty::RePlaceholder(..)
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
| ty::ReErased => Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r)),
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => {
debug!("canonical: type var found with vid {:?}", vid);
@ -339,40 +339,40 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
Err(mut ui) => {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
self.canonicalize_ty_var(
Ok(self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
},
t,
)
))
}
}
}
ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
ty::Infer(ty::IntVar(_)) => Ok(self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
t,
),
)),
ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
ty::Infer(ty::FloatVar(_)) => Ok(self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
t,
),
)),
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
}
ty::Placeholder(placeholder) => self.canonicalize_ty_var(
ty::Placeholder(placeholder) => Ok(self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
t,
),
)),
ty::Bound(debruijn, _) => {
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
t
Ok(t)
}
}
@ -403,13 +403,16 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)
} else {
t
Ok(t)
}
}
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
match ct.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
debug!("canonical: const var found with vid {:?}", vid);
@ -424,10 +427,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
Err(mut ui) => {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
return self.canonicalize_const_var(
return Ok(self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
ct,
);
));
}
}
}
@ -438,20 +441,20 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
return ct;
return Ok(ct);
}
}
ty::ConstKind::Placeholder(placeholder) => {
return self.canonicalize_const_var(
return Ok(self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
ct,
);
));
}
_ => {}
}
let flags = FlagComputation::for_const(ct);
if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { Ok(ct) }
}
}
@ -500,7 +503,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
indices: FxHashMap::default(),
binder_index: ty::INNERMOST,
};
let out_value = value.fold_with(&mut canonicalizer);
let out_value = value.fold_with(&mut canonicalizer).into_ok();
// Once we have canonicalized `out_value`, it should not
// contain anything that ties it to this inference context
@ -618,7 +621,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
let infcx = self.infcx;
let bound_to = infcx.shallow_resolve(ty_var);
if bound_to != ty_var {
self.fold_ty(bound_to)
self.fold_ty(bound_to).into_ok()
} else {
let var = self.canonical_var(info, ty_var.into());
self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
@ -637,12 +640,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
let infcx = self.infcx;
let bound_to = infcx.shallow_resolve(const_var);
if bound_to != const_var {
self.fold_const(bound_to)
self.fold_const(bound_to).into_ok()
} else {
let var = self.canonical_var(info, const_var.into());
self.tcx().mk_const(ty::Const {
val: ty::ConstKind::Bound(self.binder_index, var),
ty: self.fold_ty(const_var.ty),
ty: self.fold_ty(const_var.ty).into_ok(),
})
}
}

View File

@ -72,7 +72,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
F: FnOnce(u32) -> ty::InferTy,
{
if let Some(ty) = opt_ty {
return ty.fold_with(self);
return ty.fold_with(self).into_ok();
}
match self.ty_freshen_map.entry(key) {
@ -98,7 +98,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
F: FnOnce(u32) -> ty::InferConst<'tcx>,
{
if let Some(ct) = opt_ct {
return ct.fold_with(self);
return ct.fold_with(self).into_ok();
}
match self.const_freshen_map.entry(key) {
@ -119,11 +119,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
self.infcx.tcx
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(..) => {
// leave bound regions alone
r
Ok(r)
}
ty::ReEarlyBound(..)
@ -133,21 +133,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
| ty::ReEmpty(_)
| ty::ReErased => {
// replace all free regions with 'erased
self.tcx().lifetimes.re_erased
Ok(self.tcx().lifetimes.re_erased)
}
ty::ReStatic => {
if self.keep_static {
r
Ok(r)
} else {
self.tcx().lifetimes.re_erased
Ok(self.tcx().lifetimes.re_erased)
}
}
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
return t;
return Ok(t);
}
let tcx = self.infcx.tcx;
@ -155,10 +155,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
match *t.kind() {
ty::Infer(ty::TyVar(v)) => {
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy)
Ok(self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy))
}
ty::Infer(ty::IntVar(v)) => self.freshen_ty(
ty::Infer(ty::IntVar(v)) => Ok(self.freshen_ty(
self.infcx
.inner
.borrow_mut()
@ -167,9 +167,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
.map(|v| v.to_type(tcx)),
ty::IntVar(v),
ty::FreshIntTy,
),
)),
ty::Infer(ty::FloatVar(v)) => self.freshen_ty(
ty::Infer(ty::FloatVar(v)) => Ok(self.freshen_ty(
self.infcx
.inner
.borrow_mut()
@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
.map(|v| v.to_type(tcx)),
ty::FloatVar(v),
ty::FreshFloatTy,
),
)),
ty::Infer(ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct)) => {
if ct >= self.ty_freshen_count {
@ -189,7 +189,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
self.ty_freshen_count
);
}
t
Ok(t)
}
ty::Generator(..)
@ -221,7 +221,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
match ct.val {
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
let opt_ct = self
@ -232,12 +235,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
.probe_value(v)
.val
.known();
return self.freshen_const(
return Ok(self.freshen_const(
opt_ct,
ty::InferConst::Var(v),
ty::InferConst::Fresh,
ct.ty,
);
));
}
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count {
@ -248,7 +251,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
self.const_freshen_count,
);
}
return ct;
return Ok(ct);
}
ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {

View File

@ -161,7 +161,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
Ok(value)
} else {
Ok(value.fold_with(&mut fudger))
Ok(value.fold_with(&mut fudger).into_ok())
}
}
}
@ -180,7 +180,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Infer(ty::InferTy::TyVar(vid)) => {
if self.type_vars.0.contains(&vid) {
@ -188,7 +188,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
// Recreate it with a fresh variable here.
let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize;
let origin = self.type_vars.1[idx];
self.infcx.next_ty_var(origin)
Ok(self.infcx.next_ty_var(origin))
} else {
// This variable was created before the
// "fudging". Since we refresh all type
@ -198,48 +198,43 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
debug_assert!(
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
);
ty
Ok(ty)
}
}
ty::Infer(ty::InferTy::IntVar(vid)) => {
if self.int_vars.contains(&vid) {
self.infcx.next_int_var()
} else {
ty
}
Ok(if self.int_vars.contains(&vid) { self.infcx.next_int_var() } else { ty })
}
ty::Infer(ty::InferTy::FloatVar(vid)) => {
if self.float_vars.contains(&vid) {
self.infcx.next_float_var()
} else {
ty
}
Ok(if self.float_vars.contains(&vid) { self.infcx.next_float_var() } else { ty })
}
_ => ty.super_fold_with(self),
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
if let ty::ReVar(vid) = *r {
if self.region_vars.0.contains(&vid) {
let idx = vid.index() - self.region_vars.0.start.index();
let origin = self.region_vars.1[idx];
return self.infcx.next_region_var(origin);
return Ok(self.infcx.next_region_var(origin));
}
}
r
Ok(r)
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct {
if self.const_vars.0.contains(&vid) {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
let idx = (vid.index - self.const_vars.0.start.index) as usize;
let origin = self.const_vars.1[idx];
self.infcx.next_const_var(ty, origin)
Ok(self.infcx.next_const_var(ty, origin))
} else {
ct
Ok(ct)
}
} else {
ct.super_fold_with(self)

View File

@ -681,7 +681,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
t.fold_with(&mut self.freshener())
t.fold_with(&mut self.freshener()).into_ok()
}
/// Returns the origin of the type variable identified by `vid`, or `None`
@ -1381,7 +1381,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
where
T: TypeFoldable<'tcx>,
{
value.fold_with(&mut ShallowResolver { infcx: self })
value.fold_with(&mut ShallowResolver { infcx: self }).into_ok()
}
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
@ -1402,7 +1402,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
return value; // Avoid duplicated subst-folding.
}
let mut r = resolve::OpportunisticVarResolver::new(self);
value.fold_with(&mut r)
value.fold_with(&mut r).into_ok()
}
/// Returns the first unresolved variable contained in `T`. In the
@ -1745,12 +1745,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.infcx.shallow_resolve_ty(ty)
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
Ok(self.infcx.shallow_resolve_ty(ty))
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
Ok(if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
self.infcx
.inner
.borrow_mut()
@ -1761,7 +1764,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
.unwrap_or(ct)
} else {
ct
}
})
}
}

View File

@ -418,92 +418,94 @@ struct Instantiator<'a, 'tcx> {
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
let tcx = self.infcx.tcx;
value.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| {
if ty.references_error() {
return tcx.ty_error();
} else if let ty::Opaque(def_id, substs) = ty.kind() {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
// always true during the first phase of
// type-check, but not always true later on during
// NLL. Once we support named opaque types more fully,
// this same scenario will be able to arise during all phases.
//
// Here is an example using type alias `impl Trait`
// that indicates the distinction we are checking for:
//
// ```rust
// mod a {
// pub type Foo = impl Iterator;
// pub fn make_foo() -> Foo { .. }
// }
//
// mod b {
// fn foo() -> a::Foo { a::make_foo() }
// }
// ```
//
// Here, the return type of `foo` references an
// `Opaque` indeed, but not one whose value is
// presently being inferred. You can get into a
// similar situation with closure return types
// today:
//
// ```rust
// fn foo() -> impl Iterator { .. }
// fn bar() {
// let x = || foo(); // returns the Opaque assoc with `foo`
// }
// ```
if let Some(def_id) = def_id.as_local() {
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = self.infcx.defining_use_anchor;
let def_scope_default = || {
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
};
let (in_definition_scope, origin) =
match tcx.hir().expect_item(opaque_hir_id).kind {
// Anonymous `impl Trait`
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
impl_trait_fn: Some(parent),
origin,
..
}) => (parent == parent_def_id.to_def_id(), origin),
// Named `type Foo = impl Bar;`
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
impl_trait_fn: None,
origin,
..
}) => (
may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
origin,
),
_ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
value
.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| {
if ty.references_error() {
return tcx.ty_error();
} else if let ty::Opaque(def_id, substs) = ty.kind() {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
// always true during the first phase of
// type-check, but not always true later on during
// NLL. Once we support named opaque types more fully,
// this same scenario will be able to arise during all phases.
//
// Here is an example using type alias `impl Trait`
// that indicates the distinction we are checking for:
//
// ```rust
// mod a {
// pub type Foo = impl Iterator;
// pub fn make_foo() -> Foo { .. }
// }
//
// mod b {
// fn foo() -> a::Foo { a::make_foo() }
// }
// ```
//
// Here, the return type of `foo` references an
// `Opaque` indeed, but not one whose value is
// presently being inferred. You can get into a
// similar situation with closure return types
// today:
//
// ```rust
// fn foo() -> impl Iterator { .. }
// fn bar() {
// let x = || foo(); // returns the Opaque assoc with `foo`
// }
// ```
if let Some(def_id) = def_id.as_local() {
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = self.infcx.defining_use_anchor;
let def_scope_default = || {
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
};
if in_definition_scope {
let opaque_type_key =
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
return self.fold_opaque_ty(ty, opaque_type_key, origin);
}
let (in_definition_scope, origin) =
match tcx.hir().expect_item(opaque_hir_id).kind {
// Anonymous `impl Trait`
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
impl_trait_fn: Some(parent),
origin,
..
}) => (parent == parent_def_id.to_def_id(), origin),
// Named `type Foo = impl Bar;`
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
impl_trait_fn: None,
origin,
..
}) => (
may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
origin,
),
_ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
};
if in_definition_scope {
let opaque_type_key =
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
return self.fold_opaque_ty(ty, opaque_type_key, origin);
}
debug!(
"instantiate_opaque_types_in_map: \
debug!(
"instantiate_opaque_types_in_map: \
encountered opaque outside its definition scope \
def_id={:?}",
def_id,
);
def_id,
);
}
}
}
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
.into_ok()
}
#[instrument(skip(self), level = "debug")]
@ -556,21 +558,23 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
debug!(?predicate);
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match ty.kind() {
ty::Projection(projection_ty) => infcx.infer_projection(
self.param_env,
*projection_ty,
traits::ObligationCause::misc(self.value_span, self.body_id),
0,
&mut self.obligations,
),
_ => ty,
},
lt_op: |lt| lt,
ct_op: |ct| ct,
});
let predicate = predicate
.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match ty.kind() {
ty::Projection(projection_ty) => infcx.infer_projection(
self.param_env,
*projection_ty,
traits::ObligationCause::misc(self.value_span, self.body_id),
0,
&mut self.obligations,
),
_ => ty,
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
.into_ok();
debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {

View File

@ -30,25 +30,28 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.has_infer_types_or_consts() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
t.super_fold_with(self)
}
}
fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> Result<&'tcx Const<'tcx>, Self::Error> {
if !ct.has_infer_types_or_consts() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let ct = self.infcx.shallow_resolve(ct);
ct.super_fold_with(self)
}
}
fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
fn fold_mir_const(
&mut self,
constant: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
constant.super_fold_with(self)
}
}
@ -75,16 +78,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.has_infer_regions() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
t.super_fold_with(self)
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
Ok(match *r {
ty::ReVar(rid) => {
let resolved = self
.infcx
@ -95,12 +98,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
}
_ => r,
}
})
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if !ct.has_infer_regions() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
ct.super_fold_with(self)
}
@ -175,44 +181,31 @@ pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> Fixu
where
T: TypeFoldable<'tcx>,
{
let mut full_resolver = FullTypeResolver { infcx, err: None };
let result = value.fold_with(&mut full_resolver);
match full_resolver.err {
None => Ok(result),
Some(e) => Err(e),
}
value.fold_with(&mut FullTypeResolver { infcx })
}
// N.B. This type is not public because the protocol around checking the
// `err` field is not enforceable otherwise.
struct FullTypeResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
err: Option<FixupError<'tcx>>,
}
impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
type Error = FixupError<'tcx>;
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.needs_infer() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => {
self.err = Some(FixupError::UnresolvedTy(vid));
self.tcx().ty_error()
}
ty::Infer(ty::IntVar(vid)) => {
self.err = Some(FixupError::UnresolvedIntTy(vid));
self.tcx().ty_error()
}
ty::Infer(ty::FloatVar(vid)) => {
self.err = Some(FixupError::UnresolvedFloatTy(vid));
self.tcx().ty_error()
}
ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)),
ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)),
ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)),
ty::Infer(_) => {
bug!("Unexpected type in full type resolver: {:?}", t);
}
@ -221,28 +214,30 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReVar(rid) => self
ty::ReVar(rid) => Ok(self
.infcx
.lexical_region_resolutions
.borrow()
.as_ref()
.expect("region resolution not performed")
.resolve_var(rid),
_ => r,
.resolve_var(rid)),
_ => Ok(r),
}
}
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
c: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if !c.needs_infer() {
c // micro-optimize -- if there is nothing in this const that this fold affects...
Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c = self.infcx.shallow_resolve(c);
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
self.err = Some(FixupError::UnresolvedConst(vid));
return self.tcx().const_error(c.ty);
return Err(FixupError::UnresolvedConst(vid));
}
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);

View File

@ -24,6 +24,7 @@
#![feature(control_flow_enum)]
#![feature(min_specialization)]
#![feature(label_break_value)]
#![feature(unwrap_infallible)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]

View File

@ -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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
traits::Obligation {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {

View File

@ -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<Self, __F::Error> {
Ok(match self { #body_fold })
}
fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(

View File

@ -56,6 +56,7 @@
#![feature(try_blocks)]
#![feature(try_reserve_kind)]
#![feature(nonzero_ops)]
#![feature(unwrap_infallible)]
#![recursion_limit = "512"]
#[macro_use]

View File

@ -55,8 +55,8 @@ macro_rules! TrivialTypeFoldableImpls {
fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
self,
_: &mut F
) -> $ty {
self
) -> ::std::result::Result<$ty, F::Error> {
Ok(self)
}
fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
@ -98,7 +98,7 @@ macro_rules! EnumTypeFoldableImpl {
fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>(
self,
folder: &mut V,
) -> Self {
) -> ::std::result::Result<Self, V::Error> {
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)*
)

View File

@ -2760,11 +2760,11 @@ impl UserTypeProjection {
TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
UserTypeProjection {
base: self.base.fold_with(folder),
projs: self.projs.fold_with(folder),
}
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(UserTypeProjection {
base: self.base.fold_with(folder)?,
projs: self.projs.fold_with(folder)?,
})
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(

View File

@ -16,37 +16,39 @@ TrivialTypeFoldableAndLiftImpls! {
}
impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -140,8 +142,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
self
fn 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> {
@ -150,8 +152,11 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
}
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(Place {
local: self.local.fold_with(folder)?,
projection: self.projection.fold_with(folder)?,
})
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -161,7 +166,7 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<PlaceElem<'tcx>> {
}
impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -265,12 +272,12 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -282,19 +289,19 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<Vs: TypeVisitor<'tcx>>(
@ -312,8 +319,8 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for Field {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
self
fn 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> {
ControlFlow::CONTINUE
@ -321,8 +328,8 @@ impl<'tcx> TypeFoldable<'tcx> for Field {
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
self
fn 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> {
ControlFlow::CONTINUE
@ -330,8 +337,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
}
impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
self
fn 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> {
ControlFlow::CONTINUE
@ -339,12 +346,12 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
Constant {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_mir_const(self)
}
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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)?)),
}
}

View File

@ -9,7 +9,7 @@ pub(super) fn provide(providers: &mut ty::query::Providers) {
fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
// N.B., use `super_fold_with` here. If we used `fold_with`, it
// could invoke the `erase_regions_ty` query recursively.
ty.super_fold_with(&mut RegionEraserVisitor { tcx })
ty.super_fold_with(&mut RegionEraserVisitor { tcx }).into_ok()
}
impl<'tcx> TyCtxt<'tcx> {
@ -27,7 +27,7 @@ impl<'tcx> TyCtxt<'tcx> {
return value;
}
debug!("erase_regions({:?})", value);
let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }).into_ok();
debug!("erase_regions = {:?}", value1);
value1
}
@ -42,11 +42,11 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if ty.needs_infer() { ty.super_fold_with(self) } else { Ok(self.tcx.erase_regions_ty(ty)) }
}
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
where
T: TypeFoldable<'tcx>,
{
@ -54,7 +54,7 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
u.super_fold_with(self)
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
// because late-bound regions affect subtyping, we can't
// erase the bound/free distinction, but we can replace
// all free regions with 'erased.
@ -64,12 +64,15 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
// away. In codegen, they will always be erased to 'erased
// whenever a substitution occurs.
match *r {
ty::ReLateBound(..) => r,
_ => self.tcx.lifetimes.re_erased,
ty::ReLateBound(..) => Ok(r),
_ => Ok(self.tcx.lifetimes.re_erased),
}
}
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
fn fold_mir_const(
&mut self,
c: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
c.super_fold_with(self)
}
}

View File

@ -46,8 +46,8 @@ use std::ops::ControlFlow;
///
/// 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) -> Self;
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
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)
}
@ -179,8 +179,8 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
}
impl TypeFoldable<'tcx> for hir::Constness {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
self
fn 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> {
ControlFlow::CONTINUE
@ -193,32 +193,43 @@ impl TypeFoldable<'tcx> for hir::Constness {
/// identity fold, it should invoke `foo.fold_with(self)` to fold each
/// sub-item.
pub trait TypeFolder<'tcx>: Sized {
type Error = !;
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
where
T: TypeFoldable<'tcx>,
{
t.super_fold_with(self)
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
t.super_fold_with(self)
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
r.super_fold_with(self)
}
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
c: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
c.super_fold_with(self)
}
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
fn fold_predicate(
&mut self,
p: ty::Predicate<'tcx>,
) -> Result<ty::Predicate<'tcx>, Self::Error> {
p.super_fold_with(self)
}
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
fn fold_mir_const(
&mut self,
c: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
}
}
@ -290,19 +301,22 @@ where
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let t = ty.super_fold_with(self);
(self.ty_op)(t)
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_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let r = r.super_fold_with(self);
(self.lt_op)(r)
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_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
let ct = ct.super_fold_with(self);
(self.ct_op)(ct)
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))
}
}
@ -322,7 +336,7 @@ impl<'tcx> TyCtxt<'tcx> {
where
T: TypeFoldable<'tcx>,
{
value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)).into_ok()
}
/// Invoke `callback` on every region appearing free in `value`.
@ -470,7 +484,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
@ -478,16 +492,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
debug!(?self.current_index, "skipped bound region");
*self.skipped_regions = true;
r
Ok(r)
}
_ => {
debug!(?self.current_index, "folding free region");
(self.fold_region_fn)(r, self.current_index)
Ok((self.fold_region_fn)(r, self.current_index))
}
}
}
@ -528,19 +542,19 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
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>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
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 ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32());
return Ok(ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32()));
}
}
_ if t.has_vars_bound_at_or_above(self.current_index) => {
@ -548,10 +562,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
}
_ => {}
}
t
Ok(t)
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
if let Some(fld_r) = self.fld_r.as_mut() {
@ -562,25 +576,28 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
// debruijn index. Then we adjust it to the
// correct depth.
assert_eq!(debruijn1, ty::INNERMOST);
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
Ok(self.tcx.mk_region(ty::ReLateBound(debruijn, br)))
} else {
region
Ok(region)
};
}
}
_ => {}
}
r
Ok(r)
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
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 ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32());
return Ok(ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32()));
}
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => {
@ -588,7 +605,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
}
_ => {}
}
ct
Ok(ct)
}
}
@ -621,7 +638,7 @@ impl<'tcx> TyCtxt<'tcx> {
value
} else {
let mut replacer = BoundVarReplacer::new(self, Some(&mut real_fld_r), None, None);
value.fold_with(&mut replacer)
value.fold_with(&mut replacer).into_ok()
};
(value, region_map)
}
@ -647,7 +664,7 @@ impl<'tcx> TyCtxt<'tcx> {
} else {
let mut replacer =
BoundVarReplacer::new(self, Some(&mut fld_r), Some(&mut fld_t), Some(&mut fld_c));
value.fold_with(&mut replacer)
value.fold_with(&mut replacer).into_ok()
}
}
@ -938,36 +955,36 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
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>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, br) => {
if self.amount == 0 || debruijn < self.current_index {
r
Ok(r)
} else {
let debruijn = debruijn.shifted_in(self.amount);
let shifted = ty::ReLateBound(debruijn, br);
self.tcx.mk_region(shifted)
Ok(self.tcx.mk_region(shifted))
}
}
_ => r,
_ => Ok(r),
}
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Bound(debruijn, bound_ty) => {
if self.amount == 0 || debruijn < self.current_index {
ty
Ok(ty)
} else {
let debruijn = debruijn.shifted_in(self.amount);
self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
Ok(self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)))
}
}
@ -975,13 +992,18 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct {
if self.amount == 0 || debruijn < self.current_index {
ct
Ok(ct)
} else {
let debruijn = debruijn.shifted_in(self.amount);
self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
Ok(self
.tcx
.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }))
}
} else {
ct.super_fold_with(self)
@ -1008,7 +1030,7 @@ where
{
debug!("shift_vars(value={:?}, amount={})", value, amount);
value.fold_with(&mut Shifter::new(tcx, amount))
value.fold_with(&mut Shifter::new(tcx, amount)).into_ok()
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -1271,7 +1293,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 })
v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self }).into_ok()
}
}
@ -1284,19 +1306,22 @@ impl<'tcx> TypeFolder<'tcx> for ExposeDefaultConstSubstsFolder<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
ty.super_fold_with(self)
} else {
ty
Ok(ty)
}
}
fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
fn fold_predicate(
&mut self,
pred: ty::Predicate<'tcx>,
) -> Result<ty::Predicate<'tcx>, Self::Error> {
if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
pred.super_fold_with(self)
} else {
pred
Ok(pred)
}
}
}

View File

@ -622,7 +622,7 @@ fn polymorphize<'tcx>(
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
debug!("fold_ty: ty={:?}", ty);
match ty.kind {
ty::Closure(def_id, substs) => {
@ -631,11 +631,11 @@ fn polymorphize<'tcx>(
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
substs,
);
if substs == polymorphized_substs {
Ok(if substs == polymorphized_substs {
ty
} else {
self.tcx.mk_closure(def_id, polymorphized_substs)
}
})
}
ty::Generator(def_id, substs, movability) => {
let polymorphized_substs = polymorphize(
@ -643,11 +643,11 @@ fn polymorphize<'tcx>(
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
substs,
);
if substs == polymorphized_substs {
Ok(if substs == polymorphized_substs {
ty
} else {
self.tcx.mk_generator(def_id, polymorphized_substs, movability)
}
})
}
_ => ty.super_fold_with(self),
}
@ -669,7 +669,7 @@ fn polymorphize<'tcx>(
// ..and polymorphize any closures/generators captured as upvars.
let upvars_ty = upvars_ty.unwrap();
let polymorphized_upvars_ty = upvars_ty.fold_with(
&mut PolymorphizationFolder { tcx });
&mut PolymorphizationFolder { tcx }).into_ok();
debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
ty::GenericArg::from(polymorphized_upvars_ty)
},

View File

@ -1260,8 +1260,11 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
Ok(ParamEnv::new(self.caller_bounds().fold_with(folder)?, self.reveal().fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {

View File

@ -35,7 +35,9 @@ impl<'tcx> TyCtxt<'tcx> {
if !value.has_projections() {
value
} else {
value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
value
.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
.into_ok()
}
}
@ -103,18 +105,24 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
Ok(self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty())
}
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
fn fold_const(
&mut self,
c: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
Ok(self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const())
}
#[inline]
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
fn fold_mir_const(
&mut self,
c: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
// FIXME: This *probably* needs canonicalization too!
let arg = self.param_env.and(c);
self.tcx.normalize_mir_const_after_erasing_regions(arg)
Ok(self.tcx.normalize_mir_const_after_erasing_regions(arg))
}
}

View File

@ -2016,24 +2016,24 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
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>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
_ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
return t.super_fold_with(self);
}
_ => {}
}
t
Ok(t)
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
let name = &mut self.name;
let region = match *r {
ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
@ -2049,13 +2049,13 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
}
}
}
_ => return r,
_ => return Ok(r),
};
if let ty::ReLateBound(debruijn1, br) = *region {
assert_eq!(debruijn1, ty::INNERMOST);
self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
Ok(self.tcx.mk_region(ty::ReLateBound(self.current_index, br)))
} else {
region
Ok(region)
}
}
}
@ -2193,7 +2193,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
name: &mut name,
region_map: BTreeMap::new(),
};
let new_value = value.clone().skip_binder().fold_with(&mut folder);
let new_value = value.clone().skip_binder().fold_with(&mut folder).into_ok();
let region_map = folder.region_map;
start_or_continue(&mut self, "", "> ");
(new_value, region_map)

View File

@ -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<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
self
fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (T, U) {
(self.0.fold_with(folder), self.1.fold_with(folder))
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
Ok((self.0.fold_with(folder)?, self.1.fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -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<F: TypeFolder<'tcx>>(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<F: TypeFolder<'tcx>>(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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -718,9 +718,9 @@ EnumTypeFoldableImpl! {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
// FIXME: Reuse the `Rc` here.
Rc::new((*self).clone().fold_with(folder))
Ok(Rc::new((*self).clone().fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -729,9 +729,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
// FIXME: Reuse the `Arc` here.
Arc::new((*self).clone().fold_with(folder))
Ok(Arc::new((*self).clone().fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -740,8 +740,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
self.map_id(|value| value.fold_with(folder))
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|value| value.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -750,8 +750,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
self.map_id(|t| t.fold_with(folder))
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|t| t.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -760,8 +760,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
self.map_id(|t| t.fold_with(folder))
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|t| t.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
self.map_bound(|ty| ty.fold_with(folder))
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_bound(|ty| ty.fold_with(folder))
}
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<ty::Binder<'tcx, ty::Existentia
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<Ty<'tcx>> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
}
@ -818,24 +818,24 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
Self { instance: self.instance.fold_with(folder), promoted: self.promoted }
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(Self { instance: self.instance.fold_with(folder)?, promoted: self.promoted })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -870,26 +870,26 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
self
fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
Ok(self)
}
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_predicate(self)
}
fn super_fold_with<F: TypeFolder<'tcx>>(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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
let new = self.inner.kind.fold_with(folder)?;
Ok(folder.tcx().reuse_or_mk_predicate(self, new))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -1006,7 +1006,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
}
@ -1016,8 +1016,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
}
impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
self.map_id(|x| x.fold_with(folder))
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|x| x.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -1026,17 +1026,17 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T>
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
let ty = self.ty.fold_with(folder);
let val = self.val.fold_with(folder);
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<F: TypeFolder<'tcx>>(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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -1077,8 +1077,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
self
fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -1087,12 +1087,12 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
ty::Unevaluated {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(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,
}
})
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@ -1112,12 +1112,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
ty::Unevaluated {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(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,
}
})
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {

View File

@ -1101,6 +1101,18 @@ impl<'tcx, T> Binder<'tcx, T> {
Binder(value, self.1)
}
pub fn try_map_bound<F, U: TypeFoldable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
where
F: FnOnce(T) -> Result<U, E>,
{
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

View File

@ -153,11 +153,11 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
}
impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
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<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
// 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(&params) }
let params: SmallVec<[_; 8]> =
self.iter().map(|k| k.fold_with(folder)).collect::<Result<_, _>>()?;
if params[..] == self[..] {
Ok(self)
} else {
Ok(folder.tcx().intern_substs(&params))
}
}
}
}
@ -434,7 +439,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T {
span: Option<Span>,
) -> T {
let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
self.fold_with(&mut folder)
self.fold_with(&mut folder).into_ok()
}
}
@ -460,14 +465,14 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.binders_passed += 1;
let t = t.super_fold_with(self);
let t = t.super_fold_with(self)?;
self.binders_passed -= 1;
t
Ok(t)
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
@ -477,7 +482,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
ty::ReEarlyBound(data) => {
let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
match rk {
Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
Some(GenericArgKind::Lifetime(lt)) => Ok(self.shift_region_through_binders(lt)),
_ => {
let span = self.span.unwrap_or(DUMMY_SP);
let msg = format!(
@ -489,31 +494,37 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
}
}
}
_ => r,
_ => Ok(r),
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.potentially_needs_subst() {
return t;
return Ok(t);
}
match *t.kind() {
ty::Param(p) => self.ty_for_param(p, t),
ty::Param(p) => Ok(self.ty_for_param(p, t)),
_ => t.super_fold_with(self),
}
}
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
c: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::ConstKind::Param(p) = c.val {
self.const_for_param(p, c)
Ok(self.const_for_param(p, c))
} else {
c.super_fold_with(self)
}
}
#[inline]
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
fn fold_mir_const(
&mut self,
c: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
c.super_fold_with(self)
}
}

View File

@ -574,14 +574,14 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
if self.found_any_recursion {
return None;
}
let substs = substs.fold_with(self);
let substs = substs.fold_with(self).into_ok();
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
Some(expanded_ty) => expanded_ty,
None => {
let generic_ty = self.tcx.type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx, substs);
let expanded_ty = self.fold_ty(concrete_ty);
let expanded_ty = self.fold_ty(concrete_ty).into_ok();
self.expanded_cache.insert((def_id, substs), expanded_ty);
expanded_ty
}
@ -605,13 +605,13 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
self.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if let ty::Opaque(def_id, substs) = t.kind {
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
Ok(self.expand_opaque_ty(def_id, substs).unwrap_or(t))
} else if t.has_opaque_types() {
t.super_fold_with(self)
} else {
t
Ok(t)
}
}
}
@ -1046,25 +1046,31 @@ pub fn fold_list<'tcx, F, T>(
list: &'tcx ty::List<T>,
folder: &mut F,
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
) -> &'tcx ty::List<T>
) -> Result<&'tcx ty::List<T>, F::Error>
where
F: TypeFolder<'tcx>,
T: TypeFoldable<'tcx> + PartialEq + Copy,
{
let mut iter = list.iter();
// Look for the first element that changed
if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
let new_t = t.fold_with(folder);
if new_t == t { None } else { Some((i, new_t)) }
match iter.by_ref().enumerate().find_map(|(i, t)| match t.fold_with(folder) {
Ok(new_t) if new_t == t => None,
new_t => Some((i, new_t)),
}) {
// An element changed, prepare to intern the resulting list
let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
new_list.extend_from_slice(&list[..i]);
new_list.push(new_t);
new_list.extend(iter.map(|t| t.fold_with(folder)));
intern(folder.tcx(), &new_list)
} else {
list
Some((i, Ok(new_t))) => {
// An element changed, prepare to intern the resulting list
let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
new_list.extend_from_slice(&list[..i]);
new_list.push(new_t);
for t in iter {
new_list.push(t.fold_with(folder)?)
}
Ok(intern(folder.tcx(), &new_list))
}
Some((_, Err(err))) => {
return Err(err);
}
None => Ok(list),
}
}
@ -1086,7 +1092,7 @@ pub fn normalize_opaque_types(
check_recursion: false,
tcx,
};
val.fold_with(&mut visitor)
val.fold_with(&mut visitor).into_ok()
}
pub fn provide(providers: &mut ty::query::Providers) {

View File

@ -22,6 +22,7 @@
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
#![feature(unwrap_infallible)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]

View File

@ -65,14 +65,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
self.tcx,
self.is_tainted_by_errors(),
def_id,
map,
instantiated_ty,
span,
));
let definition_ty = instantiated_ty
.fold_with(&mut ReverseMapper::new(
self.tcx,
self.is_tainted_by_errors(),
def_id,
map,
instantiated_ty,
span,
))
.into_ok();
debug!(?definition_ty);
definition_ty
@ -123,14 +125,14 @@ impl ReverseMapper<'tcx> {
) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
self.map_missing_regions_to_empty = true;
let kind = kind.fold_with(self);
let kind = kind.fold_with(self).into_ok();
self.map_missing_regions_to_empty = false;
kind
}
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
kind.fold_with(self)
kind.fold_with(self).into_ok()
}
}
@ -140,17 +142,17 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
}
#[instrument(skip(self), level = "debug")]
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match r {
// Ignore bound regions and `'static` regions that appear in the
// type, we only need to remap regions that reference lifetimes
// from the function declaraion.
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
ty::ReLateBound(..) | ty::ReStatic => return r,
ty::ReLateBound(..) | ty::ReStatic => return Ok(r),
// If regions have been erased (by writeback), don't try to unerase
// them.
ty::ReErased => return r,
ty::ReErased => return Ok(r),
// The regions that we expect from borrow checking.
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
@ -165,10 +167,10 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
let generics = self.tcx().generics_of(self.opaque_type_def_id);
match self.map.get(&r.into()).map(|k| k.unpack()) {
Some(GenericArgKind::Lifetime(r1)) => r1,
Some(GenericArgKind::Lifetime(r1)) => Ok(r1),
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
self.tcx.lifetimes.re_root_empty
Ok(self.tcx.lifetimes.re_root_empty)
}
None if generics.parent.is_some() => {
if let Some(hidden_ty) = self.hidden_ty.take() {
@ -180,7 +182,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
)
.emit();
}
self.tcx.lifetimes.re_root_empty
Ok(self.tcx.lifetimes.re_root_empty)
}
None => {
self.tcx
@ -196,12 +198,12 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
)
.emit();
self.tcx().lifetimes.re_static
Ok(self.tcx().lifetimes.re_static)
}
}
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Closure(def_id, substs) => {
// I am a horrible monster and I pray for death. When
@ -239,7 +241,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
}
}));
self.tcx.mk_closure(def_id, substs)
Ok(self.tcx.mk_closure(def_id, substs))
}
ty::Generator(def_id, substs, movability) => {
@ -254,7 +256,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
}
}));
self.tcx.mk_generator(def_id, substs, movability)
Ok(self.tcx.mk_generator(def_id, substs, movability))
}
ty::Param(param) => {
@ -262,7 +264,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
match self.map.get(&ty.into()).map(|k| k.unpack()) {
// Found it in the substitution list; replace with the parameter from the
// opaque type.
Some(GenericArgKind::Type(t1)) => t1,
Some(GenericArgKind::Type(t1)) => Ok(t1),
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
None => {
debug!(?param, ?self.map);
@ -278,7 +280,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
)
.emit();
self.tcx().ty_error()
Ok(self.tcx().ty_error())
}
}
}
@ -287,10 +289,13 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
trace!("checking const {:?}", ct);
// Find a const parameter
match ct.val {
Ok(match ct.val {
ty::ConstKind::Param(..) => {
// Look it up in the substitution list.
match self.map.get(&ct.into()).map(|k| k.unpack()) {
@ -317,7 +322,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
}
_ => ct,
}
})
}
}

View File

@ -860,11 +860,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
self.tcx
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
(match r {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
Ok((match r {
ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(),
_ => None,
})
.unwrap_or_else(|| r.super_fold_with(self))
.unwrap_or_else(|| r.super_fold_with(self).into_ok()))
}
}

View File

@ -1898,15 +1898,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
let infcx = self.infcx;
self.var_map.entry(ty).or_insert_with(|| {
Ok(self.var_map.entry(ty).or_insert_with(|| {
infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
span: DUMMY_SP,
})
})
}))
} else {
ty.super_fold_with(self)
}
@ -1916,8 +1916,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
self.probe(|_| {
let mut selcx = SelectionContext::new(self);
let cleaned_pred =
pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
let cleaned_pred = pred
.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() })
.into_ok();
let cleaned_pred = super::project::normalize(
&mut selcx,

View File

@ -339,7 +339,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
if !needs_normalization(&value, self.param_env.reveal()) {
value
} else {
value.fold_with(self)
value.fold_with(self).into_ok()
}
}
}
@ -352,16 +352,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.universes.push(None);
let t = t.super_fold_with(self);
self.universes.pop();
t
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) {
return ty;
return Ok(ty);
}
// We try to be a little clever here as a performance optimization in
@ -387,14 +387,14 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
// replace bound vars if the current type is a `Projection` and we need
// to make sure we don't forget to fold the substs regardless.
match *ty.kind() {
Ok(match *ty.kind() {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),
Reveal::UserFacing => ty.super_fold_with(self)?,
Reveal::All => {
let recursion_limit = self.tcx().recursion_limit();
@ -408,11 +408,11 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
self.selcx.infcx().report_overflow_error(&obligation, true);
}
let substs = substs.super_fold_with(self);
let substs = substs.super_fold_with(self)?;
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.depth += 1;
let folded_ty = self.fold_ty(concrete_ty);
let folded_ty = self.fold_ty(concrete_ty)?;
self.depth -= 1;
folded_ty
}
@ -426,7 +426,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
// register an obligation to *later* project, since we know
// there won't be bound vars there.
let data = data.super_fold_with(self);
let data = data.super_fold_with(self)?;
let normalized_ty = normalize_projection_type(
self.selcx,
self.param_env,
@ -461,7 +461,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
let infcx = self.selcx.infcx();
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
let data = data.super_fold_with(self);
let data = data.super_fold_with(self)?;
let normalized_ty = opt_normalize_projection_type(
self.selcx,
self.param_env,
@ -473,16 +473,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
.ok()
.flatten()
.map(|normalized_ty| {
PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
normalized_ty,
)
Ok({
PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
normalized_ty,
)
})
})
.unwrap_or_else(|| ty.super_fold_with(self));
.unwrap_or_else(|| ty.super_fold_with(self))?;
debug!(
?self.depth,
@ -494,16 +496,19 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
normalized_ty
}
_ => ty.super_fold_with(self),
}
_ => ty.super_fold_with(self)?,
})
}
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
constant: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if self.selcx.tcx().lazy_normalization() {
constant
Ok(constant)
} else {
let constant = constant.super_fold_with(self);
constant.eval(self.selcx.tcx(), self.param_env)
let constant = constant.super_fold_with(self)?;
Ok(constant.eval(self.selcx.tcx(), self.param_env))
}
}
}
@ -550,7 +555,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
universe_indices,
};
let value = value.super_fold_with(&mut replacer);
let value = value.super_fold_with(&mut replacer).into_ok();
(value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
}
@ -577,14 +582,14 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
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>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, _)
if debruijn.as_usize() + 1
@ -596,13 +601,13 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderRegion { universe, name: br.kind };
self.mapped_regions.insert(p, br);
self.infcx.tcx.mk_region(ty::RePlaceholder(p))
Ok(self.infcx.tcx.mk_region(ty::RePlaceholder(p)))
}
_ => r,
_ => Ok(r),
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
ty::Bound(debruijn, _)
if debruijn.as_usize() + 1
@ -614,14 +619,17 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderType { universe, name: bound_ty.var };
self.mapped_types.insert(p, bound_ty);
self.infcx.tcx.mk_ty(ty::Placeholder(p))
Ok(self.infcx.tcx.mk_ty(ty::Placeholder(p)))
}
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
_ => t,
_ => Ok(t),
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
match *ct {
ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
if debruijn.as_usize() + 1
@ -638,10 +646,10 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
name: ty::BoundConst { var: bound_const, ty },
};
self.mapped_consts.insert(p, bound_const);
self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
Ok(self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty }))
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
_ => ct,
_ => Ok(ct),
}
}
}
@ -673,7 +681,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
universe_indices,
current_index: ty::INNERMOST,
};
value.super_fold_with(&mut replacer)
value.super_fold_with(&mut replacer).into_ok()
}
}
@ -685,9 +693,9 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
if !t.has_placeholders() && !t.has_infer_regions() {
return t;
return Ok(t);
}
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
@ -695,7 +703,7 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
t
}
fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r0: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
let r1 = match r0 {
ty::ReVar(_) => self
.infcx
@ -729,10 +737,10 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
debug!(?r0, ?r1, ?r2, "fold_region");
r2
Ok(r2)
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Placeholder(p) => {
let replace_var = self.mapped_types.get(&p);
@ -746,18 +754,21 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
self.tcx().mk_ty(ty::Bound(db, *replace_var))
Ok(self.tcx().mk_ty(ty::Bound(db, *replace_var)))
}
None => ty,
None => Ok(ty),
}
}
_ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
_ => ty,
_ => Ok(ty),
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
let replace_var = self.mapped_consts.get(&p);
match replace_var {
@ -770,10 +781,11 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
self.tcx()
.mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
Ok(self
.tcx()
.mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty }))
}
None => ct,
None => Ok(ct),
}
} else {
ct.super_fold_with(self)
@ -1534,7 +1546,8 @@ fn confirm_candidate<'cx, 'tcx>(
// when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters.
if progress.ty.has_infer_regions() {
progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
progress.ty =
OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty).into_ok();
}
progress
}

View File

@ -61,7 +61,6 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
cause: self.cause,
param_env: self.param_env,
obligations: vec![],
error: false,
cache: SsoHashMap::new(),
anon_depth: 0,
universes: vec![],
@ -100,11 +99,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
std::any::type_name::<T>(),
normalizer.obligations,
);
if normalizer.error {
Err(NoSolution)
} else {
Ok(Normalized { value: result, obligations: normalizer.obligations })
}
result.map(|value| Normalized { value, obligations: normalizer.obligations })
}
}
@ -171,12 +166,13 @@ struct QueryNormalizer<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
error: bool,
anon_depth: usize,
universes: Vec<Option<ty::UniverseIndex>>,
}
impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
type Error = NoSolution;
fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
@ -184,7 +180,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.universes.push(None);
let t = t.super_fold_with(self);
self.universes.pop();
@ -192,13 +188,13 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
}
#[instrument(level = "debug", skip(self))]
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) {
return ty;
return Ok(ty);
}
if let Some(ty) = self.cache.get(&ty) {
return ty;
return Ok(ty);
}
// See note in `rustc_trait_selection::traits::project` about why we
@ -215,7 +211,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
Reveal::UserFacing => ty.super_fold_with(self),
Reveal::All => {
let substs = substs.super_fold_with(self);
let substs = substs.super_fold_with(self)?;
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
let obligation = Obligation::with_depth(
@ -252,7 +248,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
// we don't need to replace them with placeholders (see branch below).
let tcx = self.infcx.tcx;
let data = data.super_fold_with(self);
let data = data.super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
@ -262,39 +258,22 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
match tcx.normalize_projection_ty(c_data) {
Ok(result) => {
// We don't expect ambiguity.
if result.is_ambiguous() {
self.error = true;
return ty.super_fold_with(self);
}
match self.infcx.instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
result,
) {
Ok(InferOk { value: result, obligations }) => {
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
result.normalized_ty
}
Err(_) => {
self.error = true;
ty.super_fold_with(self)
}
}
}
Err(NoSolution) => {
self.error = true;
ty.super_fold_with(self)
}
let result = tcx.normalize_projection_ty(c_data)?;
// We don't expect ambiguity.
if result.is_ambiguous() {
return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
result,
)?;
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
Ok(result.normalized_ty)
}
ty::Projection(data) => {
@ -308,7 +287,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
&mut self.universes,
data,
);
let data = data.super_fold_with(self);
let data = data.super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
@ -318,57 +297,49 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
match tcx.normalize_projection_ty(c_data) {
Ok(result) => {
// We don't expect ambiguity.
if result.is_ambiguous() {
self.error = true;
return ty.super_fold_with(self);
}
match self.infcx.instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
result,
) {
Ok(InferOk { value: result, obligations }) => {
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
crate::traits::project::PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.normalized_ty,
)
}
Err(_) => {
self.error = true;
ty.super_fold_with(self)
}
}
}
Err(NoSolution) => {
self.error = true;
ty.super_fold_with(self)
}
let result = tcx.normalize_projection_ty(c_data)?;
// We don't expect ambiguity.
if result.is_ambiguous() {
return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
result,
)?;
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.normalized_ty,
))
}
_ => ty.super_fold_with(self),
})();
})()?;
self.cache.insert(ty, res);
res
Ok(res)
}
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
let constant = constant.super_fold_with(self);
constant.eval(self.infcx.tcx, self.param_env)
fn fold_const(
&mut self,
constant: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
let constant = constant.super_fold_with(self)?;
Ok(constant.eval(self.infcx.tcx, self.param_env))
}
fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
fn fold_mir_const(
&mut self,
constant: mir::ConstantKind<'tcx>,
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
constant.super_fold_with(self)
}
}

View File

@ -2222,6 +2222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.predicate
.to_poly_trait_ref()
.fold_with(&mut self.freshener)
.into_ok()
.with_constness(obligation.predicate.skip_binder().constness);
let dfn = previous_stack.cache.next_dfn();

View File

@ -45,7 +45,7 @@ impl<'tcx> RustIrDatabase<'tcx> {
predicates
.iter()
.map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
.map(|wc| wc.fold_with(&mut regions_substitutor))
.map(|wc| wc.fold_with(&mut regions_substitutor).into_ok())
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect()
}
@ -287,7 +287,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
let mut regions_substitutor =
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
let trait_ref = trait_ref.fold_with(&mut regions_substitutor).into_ok();
let where_clauses = self.where_clauses_for(def_id, bound_vars);
@ -335,7 +335,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
let mut regions_substitutor =
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
let self_ty = self_ty.fold_with(&mut regions_substitutor);
let self_ty = self_ty.fold_with(&mut regions_substitutor).into_ok();
let lowered_ty = self_ty.lower_into(&self.interner);
parameters[0].assert_ty_ref(&self.interner).could_match(
@ -501,22 +501,24 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
.iter()
.map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
.map(|bound| {
bound.fold_with(&mut ty::fold::BottomUpFolder {
tcx: self.interner.tcx,
ty_op: |ty| {
if let ty::Opaque(def_id, substs) = *ty.kind() {
if def_id == opaque_ty_id.0 && substs == identity_substs {
return self.interner.tcx.mk_ty(ty::Bound(
ty::INNERMOST,
ty::BoundTy::from(ty::BoundVar::from_u32(0)),
));
bound
.fold_with(&mut ty::fold::BottomUpFolder {
tcx: self.interner.tcx,
ty_op: |ty| {
if let ty::Opaque(def_id, substs) = *ty.kind() {
if def_id == opaque_ty_id.0 && substs == identity_substs {
return self.interner.tcx.mk_ty(ty::Bound(
ty::INNERMOST,
ty::BoundTy::from(ty::BoundVar::from_u32(0)),
));
}
}
}
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
.into_ok()
})
.filter_map(|bound| {
LowerInto::<

View File

@ -817,7 +817,7 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>(
.collect();
let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters);
let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor).into_ok();
for var in named_parameters.values() {
parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
@ -943,20 +943,23 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> {
self.tcx
}
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: Binder<'tcx, T>,
) -> Result<Binder<'tcx, T>, Self::Error> {
self.binder_index.shift_in(1);
let result = t.super_fold_with(self);
self.binder_index.shift_out(1);
result
}
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
Some(idx) => {
let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br));
return Ok(self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)));
}
None => panic!("Missing `BrNamed`."),
},
@ -999,32 +1002,35 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
self.tcx
}
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: Binder<'tcx, T>,
) -> Result<Binder<'tcx, T>, Self::Error> {
self.binder_index.shift_in(1);
let result = t.super_fold_with(self);
self.binder_index.shift_out(1);
result
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
// FIXME(chalk): currently we convert params to placeholders starting at
// index `0`. To support placeholders, we'll actually need to do a
// first pass to collect placeholders. Then we can insert params after.
ty::Placeholder(_) => unimplemented!(),
ty::Param(param) => match self.list.iter().position(|r| r == &param) {
Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
Some(idx) => Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::from_usize(0),
name: ty::BoundVar::from_usize(idx),
})),
}))),
None => {
self.list.push(param);
let idx = self.list.len() - 1 + self.next_ty_placeholder;
self.params.insert(idx, param);
self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::from_usize(0),
name: ty::BoundVar::from_usize(idx),
}))
})))
}
},
@ -1032,7 +1038,7 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
}
}
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
match r {
// FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
// This covers any region variables in a goal, right?
@ -1042,14 +1048,14 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
var: ty::BoundVar::from_u32(*idx),
kind: ty::BrAnon(*idx),
};
self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
}
None => {
let idx = self.named_regions.len() as u32;
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
self.named_regions.insert(_re.def_id, idx);
self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
}
},
@ -1125,11 +1131,11 @@ impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> {
self.tcx
}
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
match r {
ty::ReEmpty(ui) => {
assert_eq!(ui.as_usize(), 0);
self.reempty_placeholder
Ok(self.reempty_placeholder)
}
_ => r.super_fold_with(self),

View File

@ -49,12 +49,12 @@ crate fn evaluate_goal<'tcx>(
let mut params_substitutor =
ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
let obligation = obligation.fold_with(&mut params_substitutor);
let obligation = obligation.fold_with(&mut params_substitutor).into_ok();
// FIXME(chalk): we really should be substituting these back in the solution
let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
let obligation = obligation.fold_with(&mut regions_substitutor);
let obligation = obligation.fold_with(&mut regions_substitutor).into_ok();
let max_universe = obligation.max_universe.index();

View File

@ -4,6 +4,7 @@
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]

View File

@ -442,8 +442,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut eraser = TypeParamEraser(self, expr.span);
let needs_bound = self
.lookup_op_method(
eraser.fold_ty(lhs_ty),
&[eraser.fold_ty(rhs_ty)],
eraser.fold_ty(lhs_ty).into_ok(),
&[eraser.fold_ty(rhs_ty).into_ok()],
Op::Binary(op, is_assign),
)
.is_ok();
@ -1015,12 +1015,12 @@ impl TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
self.0.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match ty.kind() {
ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
ty::Param(_) => Ok(self.0.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: self.1,
}),
})),
_ => ty.super_fold_with(self),
}
}

View File

@ -658,7 +658,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
T: TypeFoldable<'tcx>,
{
let mut resolver = Resolver::new(self.fcx, span, self.body);
let x = x.fold_with(&mut resolver);
let x = x.fold_with(&mut resolver).into_ok();
if cfg!(debug_assertions) && x.needs_infer() {
span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x);
}
@ -749,15 +749,15 @@ impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
ty.super_fold_with(self)
} else {
ty
Ok(ty)
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
Ok(if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased })
}
}
@ -766,7 +766,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
self.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match self.infcx.fully_resolve(t) {
Ok(t) => {
// Do not anonymize late-bound regions
@ -779,18 +779,21 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
self.report_type_error(t);
self.replaced_with_error = true;
self.tcx().ty_error()
Ok(self.tcx().ty_error())
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
debug_assert!(!r.is_late_bound(), "Should not be resolving bound region.");
self.tcx.lifetimes.re_erased
Ok(self.tcx.lifetimes.re_erased)
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match self.infcx.fully_resolve(ct) {
fn fold_const(
&mut self,
ct: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
Ok(match self.infcx.fully_resolve(ct) {
Ok(ct) => self.infcx.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
@ -798,7 +801,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
self.replaced_with_error = true;
self.tcx().const_error(ct.ty)
}
}
})
}
}

View File

@ -729,17 +729,17 @@ fn infer_placeholder_type<'a>(
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !self.success {
return ty;
return Ok(ty);
}
match ty.kind() {
ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
ty::FnDef(def_id, _) => Ok(self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id))),
// FIXME: non-capturing closures should also suggest a function pointer
ty::Closure(..) | ty::Generator(..) => {
self.success = false;
ty
Ok(ty)
}
_ => ty.super_fold_with(self),
}
@ -761,7 +761,7 @@ fn infer_placeholder_type<'a>(
// Suggesting unnameable types won't help.
let mut mk_nameable = MakeNameable::new(tcx);
let ty = mk_nameable.fold_ty(ty);
let ty = mk_nameable.fold_ty(ty).into_ok();
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
err.span_suggestion(
@ -785,7 +785,7 @@ fn infer_placeholder_type<'a>(
if !ty.references_error() {
let mut mk_nameable = MakeNameable::new(tcx);
let ty = mk_nameable.fold_ty(ty);
let ty = mk_nameable.fold_ty(ty).into_ok();
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
diag.span_suggestion(

View File

@ -71,8 +71,11 @@ fn diagnostic_hir_wf_check<'tcx>(
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
self.tcx.infer_ctxt().enter(|infcx| {
let mut fulfill = traits::FulfillmentContext::new();
let tcx_ty =
self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
let tcx_ty = self
.icx
.to_ty(ty)
.fold_with(&mut EraseAllBoundRegions { tcx: self.tcx })
.into_ok();
let cause = traits::ObligationCause::new(
ty.span,
self.hir_id,
@ -183,7 +186,7 @@ impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
if let ty::ReLateBound(..) = r { &ty::ReErased } else { r }
fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
if let ty::ReLateBound(..) = r { Ok(&ty::ReErased) } else { Ok(r) }
}
}

View File

@ -71,6 +71,7 @@ This API is completely unstable and subject to change.
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
#![feature(hash_drain_filter)]
#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]

View File

@ -449,7 +449,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
_ => false,
}
})
.map(|p| p.fold_with(&mut replacer));
.map(|p| p.fold_with(&mut replacer).into_ok());
let mut generic_params =
(tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id))
@ -714,11 +714,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
self.tcx
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
(match *r {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
Ok((match *r {
ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
_ => None,
})
.unwrap_or_else(|| r.super_fold_with(self))
.unwrap_or_else(|| r.super_fold_with(self).into_ok()))
}
}

View File

@ -18,6 +18,7 @@
#![feature(type_ascription)]
#![feature(iter_intersperse)]
#![recursion_limit = "256"]
#![feature(unwrap_infallible)]
#![warn(rustc::internal)]
#[macro_use]