Skip to content

Commit e6d2de9

Browse files
committed
Auto merge of rust-lang#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 rust-lang#85469 (abandoned; see rust-lang#85485 (comment)). 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`
2 parents 58f9efd + afa6f92 commit e6d2de9

File tree

45 files changed

+905
-791
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+905
-791
lines changed

compiler/rustc_const_eval/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust.
2323
#![feature(trusted_len)]
2424
#![feature(trusted_step)]
2525
#![feature(try_blocks)]
26+
#![feature(unwrap_infallible)]
2627
#![recursion_limit = "256"]
2728

2829
#[macro_use]

compiler/rustc_const_eval/src/transform/validate.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ pub fn equal_up_to_regions(
9595
// Leave consts and types unchanged.
9696
ct_op: |ct| ct,
9797
ty_op: |ty| ty,
98-
}),
98+
})
99+
.into_ok(),
99100
)
100101
};
101102
tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
+42-20
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,52 @@
11
use rustc_index::vec::{Idx, IndexVec};
22
use std::mem;
3-
use std::ptr;
43

5-
pub trait IdFunctor {
4+
pub trait IdFunctor: Sized {
65
type Inner;
76

8-
fn map_id<F>(self, f: F) -> Self
7+
#[inline]
8+
fn map_id<F>(self, mut f: F) -> Self
9+
where
10+
F: FnMut(Self::Inner) -> Self::Inner,
11+
{
12+
self.try_map_id::<_, !>(|value| Ok(f(value))).into_ok()
13+
}
14+
15+
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
916
where
10-
F: FnMut(Self::Inner) -> Self::Inner;
17+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
1118
}
1219

1320
impl<T> IdFunctor for Box<T> {
1421
type Inner = T;
1522

1623
#[inline]
17-
fn map_id<F>(self, mut f: F) -> Self
24+
fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
1825
where
19-
F: FnMut(Self::Inner) -> Self::Inner,
26+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
2027
{
2128
let raw = Box::into_raw(self);
22-
unsafe {
29+
Ok(unsafe {
2330
// SAFETY: The raw pointer points to a valid value of type `T`.
24-
let value = ptr::read(raw);
31+
let value = raw.read();
2532
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
2633
// inverse of `Box::assume_init()` and should be safe.
2734
let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
2835
// SAFETY: Write the mapped value back into the `Box`.
29-
raw.write(f(value));
36+
raw.write(f(value)?);
3037
// SAFETY: We just initialized `raw`.
3138
raw.assume_init()
32-
}
39+
})
3340
}
3441
}
3542

3643
impl<T> IdFunctor for Vec<T> {
3744
type Inner = T;
3845

3946
#[inline]
40-
fn map_id<F>(mut self, mut f: F) -> Self
47+
fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
4148
where
42-
F: FnMut(Self::Inner) -> Self::Inner,
49+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
4350
{
4451
// FIXME: We don't really care about panics here and leak
4552
// far more than we should, but that should be fine for now.
@@ -49,34 +56,49 @@ impl<T> IdFunctor for Vec<T> {
4956
let start = self.as_mut_ptr();
5057
for i in 0..len {
5158
let p = start.add(i);
52-
ptr::write(p, f(ptr::read(p)));
59+
match f(p.read()) {
60+
Ok(val) => p.write(val),
61+
Err(err) => {
62+
// drop all other elements in self
63+
// (current element was "moved" into the call to f)
64+
for j in (0..i).chain(i + 1..len) {
65+
start.add(j).drop_in_place();
66+
}
67+
68+
// returning will drop self, releasing the allocation
69+
// (len is 0 so elements will not be re-dropped)
70+
return Err(err);
71+
}
72+
}
5373
}
74+
// Even if we encountered an error, set the len back
75+
// so we don't leak memory.
5476
self.set_len(len);
5577
}
56-
self
78+
Ok(self)
5779
}
5880
}
5981

6082
impl<T> IdFunctor for Box<[T]> {
6183
type Inner = T;
6284

6385
#[inline]
64-
fn map_id<F>(self, f: F) -> Self
86+
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
6587
where
66-
F: FnMut(Self::Inner) -> Self::Inner,
88+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
6789
{
68-
Vec::from(self).map_id(f).into()
90+
Vec::from(self).try_map_id(f).map(Into::into)
6991
}
7092
}
7193

7294
impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
7395
type Inner = T;
7496

7597
#[inline]
76-
fn map_id<F>(self, f: F) -> Self
98+
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
7799
where
78-
F: FnMut(Self::Inner) -> Self::Inner,
100+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
79101
{
80-
IndexVec::from_raw(self.raw.map_id(f))
102+
self.raw.try_map_id(f).map(IndexVec::from_raw)
81103
}
82104
}

compiler/rustc_data_structures/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(once_cell)]
2626
#![feature(test)]
2727
#![feature(thread_id_value)]
28+
#![feature(unwrap_infallible)]
2829
#![allow(rustc::default_hash_types)]
2930
#![deny(unaligned_references)]
3031

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

+30-27
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
278278
self.tcx
279279
}
280280

281-
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
281+
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
282282
where
283283
T: TypeFoldable<'tcx>,
284284
{
@@ -288,13 +288,13 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
288288
t
289289
}
290290

291-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
291+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
292292
match *r {
293293
ty::ReLateBound(index, ..) => {
294294
if index >= self.binder_index {
295295
bug!("escaping late-bound region during canonicalization");
296296
} else {
297-
r
297+
Ok(r)
298298
}
299299
}
300300

@@ -311,19 +311,19 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
311311
vid, r
312312
);
313313
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
314-
self.canonicalize_region_mode.canonicalize_free_region(self, r)
314+
Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r))
315315
}
316316

317317
ty::ReStatic
318318
| ty::ReEarlyBound(..)
319319
| ty::ReFree(_)
320320
| ty::ReEmpty(_)
321321
| ty::RePlaceholder(..)
322-
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
322+
| ty::ReErased => Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r)),
323323
}
324324
}
325325

326-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
326+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
327327
match *t.kind() {
328328
ty::Infer(ty::TyVar(vid)) => {
329329
debug!("canonical: type var found with vid {:?}", vid);
@@ -339,40 +339,40 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
339339
Err(mut ui) => {
340340
// FIXME: perf problem described in #55921.
341341
ui = ty::UniverseIndex::ROOT;
342-
self.canonicalize_ty_var(
342+
Ok(self.canonicalize_ty_var(
343343
CanonicalVarInfo {
344344
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
345345
},
346346
t,
347-
)
347+
))
348348
}
349349
}
350350
}
351351

352-
ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
352+
ty::Infer(ty::IntVar(_)) => Ok(self.canonicalize_ty_var(
353353
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
354354
t,
355-
),
355+
)),
356356

357-
ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
357+
ty::Infer(ty::FloatVar(_)) => Ok(self.canonicalize_ty_var(
358358
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
359359
t,
360-
),
360+
)),
361361

362362
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
363363
bug!("encountered a fresh type during canonicalization")
364364
}
365365

366-
ty::Placeholder(placeholder) => self.canonicalize_ty_var(
366+
ty::Placeholder(placeholder) => Ok(self.canonicalize_ty_var(
367367
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
368368
t,
369-
),
369+
)),
370370

371371
ty::Bound(debruijn, _) => {
372372
if debruijn >= self.binder_index {
373373
bug!("escaping bound type during canonicalization")
374374
} else {
375-
t
375+
Ok(t)
376376
}
377377
}
378378

@@ -403,13 +403,16 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
403403
if t.flags().intersects(self.needs_canonical_flags) {
404404
t.super_fold_with(self)
405405
} else {
406-
t
406+
Ok(t)
407407
}
408408
}
409409
}
410410
}
411411

412-
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
412+
fn fold_const(
413+
&mut self,
414+
ct: &'tcx ty::Const<'tcx>,
415+
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
413416
match ct.val {
414417
ty::ConstKind::Infer(InferConst::Var(vid)) => {
415418
debug!("canonical: const var found with vid {:?}", vid);
@@ -424,10 +427,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
424427
Err(mut ui) => {
425428
// FIXME: perf problem described in #55921.
426429
ui = ty::UniverseIndex::ROOT;
427-
return self.canonicalize_const_var(
430+
return Ok(self.canonicalize_const_var(
428431
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
429432
ct,
430-
);
433+
));
431434
}
432435
}
433436
}
@@ -438,20 +441,20 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
438441
if debruijn >= self.binder_index {
439442
bug!("escaping bound type during canonicalization")
440443
} else {
441-
return ct;
444+
return Ok(ct);
442445
}
443446
}
444447
ty::ConstKind::Placeholder(placeholder) => {
445-
return self.canonicalize_const_var(
448+
return Ok(self.canonicalize_const_var(
446449
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
447450
ct,
448-
);
451+
));
449452
}
450453
_ => {}
451454
}
452455

453456
let flags = FlagComputation::for_const(ct);
454-
if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
457+
if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { Ok(ct) }
455458
}
456459
}
457460

@@ -500,7 +503,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
500503
indices: FxHashMap::default(),
501504
binder_index: ty::INNERMOST,
502505
};
503-
let out_value = value.fold_with(&mut canonicalizer);
506+
let out_value = value.fold_with(&mut canonicalizer).into_ok();
504507

505508
// Once we have canonicalized `out_value`, it should not
506509
// contain anything that ties it to this inference context
@@ -618,7 +621,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
618621
let infcx = self.infcx;
619622
let bound_to = infcx.shallow_resolve(ty_var);
620623
if bound_to != ty_var {
621-
self.fold_ty(bound_to)
624+
self.fold_ty(bound_to).into_ok()
622625
} else {
623626
let var = self.canonical_var(info, ty_var.into());
624627
self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
@@ -637,12 +640,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
637640
let infcx = self.infcx;
638641
let bound_to = infcx.shallow_resolve(const_var);
639642
if bound_to != const_var {
640-
self.fold_const(bound_to)
643+
self.fold_const(bound_to).into_ok()
641644
} else {
642645
let var = self.canonical_var(info, const_var.into());
643646
self.tcx().mk_const(ty::Const {
644647
val: ty::ConstKind::Bound(self.binder_index, var),
645-
ty: self.fold_ty(const_var.ty),
648+
ty: self.fold_ty(const_var.ty).into_ok(),
646649
})
647650
}
648651
}

0 commit comments

Comments
 (0)