Skip to content

Commit 207d6e1

Browse files
authored
Rollup merge of #108039 - eggyal:traverse_refcounts_via_functors, r=oli-obk
Refactor refcounted structural_impls via functors The mapping of values in refcounted types can be extracted as a functor, simplifying the implementations in the type library (whose structural folding impls now all use such functors). This functor could also prove more generally useful elsewhere.
2 parents edcdab0 + 26e3363 commit 207d6e1

File tree

4 files changed

+55
-69
lines changed

4 files changed

+55
-69
lines changed

Diff for: compiler/rustc_data_structures/src/functor.rs

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_index::vec::{Idx, IndexVec};
2-
use std::mem;
2+
use std::{mem, rc::Rc, sync::Arc};
33

44
pub trait IdFunctor: Sized {
55
type Inner;
@@ -65,3 +65,52 @@ impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
6565
self.raw.try_map_id(f).map(IndexVec::from_raw)
6666
}
6767
}
68+
69+
macro_rules! rc {
70+
($($rc:ident),+) => {$(
71+
impl<T: Clone> IdFunctor for $rc<T> {
72+
type Inner = T;
73+
74+
#[inline]
75+
fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
76+
where
77+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
78+
{
79+
// We merely want to replace the contained `T`, if at all possible,
80+
// so that we don't needlessly allocate a new `$rc` or indeed clone
81+
// the contained type.
82+
unsafe {
83+
// First step is to ensure that we have a unique reference to
84+
// the contained type, which `$rc::make_mut` will accomplish (by
85+
// allocating a new `$rc` and cloning the `T` only if required).
86+
// This is done *before* casting to `$rc<ManuallyDrop<T>>` so that
87+
// panicking during `make_mut` does not leak the `T`.
88+
$rc::make_mut(&mut self);
89+
90+
// Casting to `$rc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
91+
// is `repr(transparent)`.
92+
let ptr = $rc::into_raw(self).cast::<mem::ManuallyDrop<T>>();
93+
let mut unique = $rc::from_raw(ptr);
94+
95+
// Call to `$rc::make_mut` above guarantees that `unique` is the
96+
// sole reference to the contained value, so we can avoid doing
97+
// a checked `get_mut` here.
98+
let slot = $rc::get_mut_unchecked(&mut unique);
99+
100+
// Semantically move the contained type out from `unique`, fold
101+
// it, then move the folded value back into `unique`. Should
102+
// folding fail, `ManuallyDrop` ensures that the "moved-out"
103+
// value is not re-dropped.
104+
let owned = mem::ManuallyDrop::take(slot);
105+
let folded = f(owned)?;
106+
*slot = mem::ManuallyDrop::new(folded);
107+
108+
// Cast back to `$rc<T>`.
109+
Ok($rc::from_raw($rc::into_raw(unique).cast()))
110+
}
111+
}
112+
}
113+
)+};
114+
}
115+
116+
rc! { Rc, Arc }

Diff for: compiler/rustc_data_structures/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#![feature(test)]
2727
#![feature(thread_id_value)]
2828
#![feature(vec_into_raw_parts)]
29+
#![feature(get_mut_unchecked)]
2930
#![allow(rustc::default_hash_types)]
3031
#![allow(rustc::potential_query_instability)]
3132
#![deny(rustc::untranslatable_diagnostic)]

Diff for: compiler/rustc_type_ir/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![feature(associated_type_defaults)]
22
#![feature(fmt_helpers_for_derive)]
3-
#![feature(get_mut_unchecked)]
43
#![feature(min_specialization)]
54
#![feature(never_type)]
65
#![feature(rustc_attrs)]

Diff for: compiler/rustc_type_ir/src/structural_impls.rs

+4-67
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::Interner;
88
use rustc_data_structures::functor::IdFunctor;
99
use rustc_index::vec::{Idx, IndexVec};
1010

11-
use std::mem::ManuallyDrop;
1211
use std::ops::ControlFlow;
1312
use std::rc::Rc;
1413
use std::sync::Arc;
@@ -98,39 +97,8 @@ EnumTypeTraversalImpl! {
9897
}
9998

10099
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Rc<T> {
101-
fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
102-
// We merely want to replace the contained `T`, if at all possible,
103-
// so that we don't needlessly allocate a new `Rc` or indeed clone
104-
// the contained type.
105-
unsafe {
106-
// First step is to ensure that we have a unique reference to
107-
// the contained type, which `Rc::make_mut` will accomplish (by
108-
// allocating a new `Rc` and cloning the `T` only if required).
109-
// This is done *before* casting to `Rc<ManuallyDrop<T>>` so that
110-
// panicking during `make_mut` does not leak the `T`.
111-
Rc::make_mut(&mut self);
112-
113-
// Casting to `Rc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
114-
// is `repr(transparent)`.
115-
let ptr = Rc::into_raw(self).cast::<ManuallyDrop<T>>();
116-
let mut unique = Rc::from_raw(ptr);
117-
118-
// Call to `Rc::make_mut` above guarantees that `unique` is the
119-
// sole reference to the contained value, so we can avoid doing
120-
// a checked `get_mut` here.
121-
let slot = Rc::get_mut_unchecked(&mut unique);
122-
123-
// Semantically move the contained type out from `unique`, fold
124-
// it, then move the folded value back into `unique`. Should
125-
// folding fail, `ManuallyDrop` ensures that the "moved-out"
126-
// value is not re-dropped.
127-
let owned = ManuallyDrop::take(slot);
128-
let folded = owned.try_fold_with(folder)?;
129-
*slot = ManuallyDrop::new(folded);
130-
131-
// Cast back to `Rc<T>`.
132-
Ok(Rc::from_raw(Rc::into_raw(unique).cast()))
133-
}
100+
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
101+
self.try_map_id(|value| value.try_fold_with(folder))
134102
}
135103
}
136104

@@ -141,39 +109,8 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Rc<T> {
141109
}
142110

143111
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> {
144-
fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
145-
// We merely want to replace the contained `T`, if at all possible,
146-
// so that we don't needlessly allocate a new `Arc` or indeed clone
147-
// the contained type.
148-
unsafe {
149-
// First step is to ensure that we have a unique reference to
150-
// the contained type, which `Arc::make_mut` will accomplish (by
151-
// allocating a new `Arc` and cloning the `T` only if required).
152-
// This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
153-
// panicking during `make_mut` does not leak the `T`.
154-
Arc::make_mut(&mut self);
155-
156-
// Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
157-
// is `repr(transparent)`.
158-
let ptr = Arc::into_raw(self).cast::<ManuallyDrop<T>>();
159-
let mut unique = Arc::from_raw(ptr);
160-
161-
// Call to `Arc::make_mut` above guarantees that `unique` is the
162-
// sole reference to the contained value, so we can avoid doing
163-
// a checked `get_mut` here.
164-
let slot = Arc::get_mut_unchecked(&mut unique);
165-
166-
// Semantically move the contained type out from `unique`, fold
167-
// it, then move the folded value back into `unique`. Should
168-
// folding fail, `ManuallyDrop` ensures that the "moved-out"
169-
// value is not re-dropped.
170-
let owned = ManuallyDrop::take(slot);
171-
let folded = owned.try_fold_with(folder)?;
172-
*slot = ManuallyDrop::new(folded);
173-
174-
// Cast back to `Arc<T>`.
175-
Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
176-
}
112+
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
113+
self.try_map_id(|value| value.try_fold_with(folder))
177114
}
178115
}
179116

0 commit comments

Comments
 (0)