5
5
use crate :: fold:: { FallibleTypeFolder , TypeFoldable } ;
6
6
use crate :: visit:: { TypeVisitable , TypeVisitor } ;
7
7
use crate :: { ConstKind , FloatTy , InferTy , IntTy , Interner , UintTy , UniverseIndex } ;
8
- use rustc_data_structures:: functor:: IdFunctor ;
9
8
use rustc_data_structures:: sync:: Lrc ;
10
9
use rustc_index:: { Idx , IndexVec } ;
11
10
12
11
use core:: fmt;
13
12
use std:: marker:: PhantomData ;
13
+ use std:: mem;
14
14
use std:: ops:: ControlFlow ;
15
15
16
16
///////////////////////////////////////////////////////////////////////////
@@ -108,8 +108,39 @@ impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for
108
108
}
109
109
110
110
impl < I : Interner , T : TypeFoldable < I > > TypeFoldable < I > for Lrc < T > {
111
- fn try_fold_with < F : FallibleTypeFolder < I > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
112
- self . try_map_id ( |value| value. try_fold_with ( folder) )
111
+ fn try_fold_with < F : FallibleTypeFolder < I > > ( mut self , folder : & mut F ) -> Result < Self , F :: Error > {
112
+ // We merely want to replace the contained `T`, if at all possible,
113
+ // so that we don't needlessly allocate a new `Lrc` or indeed clone
114
+ // the contained type.
115
+ unsafe {
116
+ // First step is to ensure that we have a unique reference to
117
+ // the contained type, which `Lrc::make_mut` will accomplish (by
118
+ // allocating a new `Lrc` and cloning the `T` only if required).
119
+ // This is done *before* casting to `Lrc<ManuallyDrop<T>>` so that
120
+ // panicking during `make_mut` does not leak the `T`.
121
+ Lrc :: make_mut ( & mut self ) ;
122
+
123
+ // Casting to `Lrc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
124
+ // is `repr(transparent)`.
125
+ let ptr = Lrc :: into_raw ( self ) . cast :: < mem:: ManuallyDrop < T > > ( ) ;
126
+ let mut unique = Lrc :: from_raw ( ptr) ;
127
+
128
+ // Call to `Lrc::make_mut` above guarantees that `unique` is the
129
+ // sole reference to the contained value, so we can avoid doing
130
+ // a checked `get_mut` here.
131
+ let slot = Lrc :: get_mut_unchecked ( & mut unique) ;
132
+
133
+ // Semantically move the contained type out from `unique`, fold
134
+ // it, then move the folded value back into `unique`. Should
135
+ // folding fail, `ManuallyDrop` ensures that the "moved-out"
136
+ // value is not re-dropped.
137
+ let owned = mem:: ManuallyDrop :: take ( slot) ;
138
+ let folded = owned. try_fold_with ( folder) ?;
139
+ * slot = mem:: ManuallyDrop :: new ( folded) ;
140
+
141
+ // Cast back to `Lrc<T>`.
142
+ Ok ( Lrc :: from_raw ( Lrc :: into_raw ( unique) . cast ( ) ) )
143
+ }
113
144
}
114
145
}
115
146
@@ -121,7 +152,16 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Lrc<T> {
121
152
122
153
impl < I : Interner , T : TypeFoldable < I > > TypeFoldable < I > for Box < T > {
123
154
fn try_fold_with < F : FallibleTypeFolder < I > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
124
- self . try_map_id ( |value| value. try_fold_with ( folder) )
155
+ let raw = Box :: into_raw ( self ) ;
156
+ Ok ( unsafe {
157
+ // SAFETY: The raw pointer points to a valid value of type `T`.
158
+ let value = raw. read ( ) ;
159
+ // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
160
+ // inverse of `Box::assume_init()` and should be safe.
161
+ let raw: Box < mem:: MaybeUninit < T > > = Box :: from_raw ( raw. cast ( ) ) ;
162
+ // SAFETY: Write the mapped value back into the `Box`.
163
+ Box :: write ( raw, value. try_fold_with ( folder) ?)
164
+ } )
125
165
}
126
166
}
127
167
@@ -133,7 +173,7 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> {
133
173
134
174
impl < I : Interner , T : TypeFoldable < I > > TypeFoldable < I > for Vec < T > {
135
175
fn try_fold_with < F : FallibleTypeFolder < I > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
136
- self . try_map_id ( |t| t. try_fold_with ( folder) )
176
+ self . into_iter ( ) . map ( |t| t. try_fold_with ( folder) ) . collect ( )
137
177
}
138
178
}
139
179
@@ -161,7 +201,7 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
161
201
162
202
impl < I : Interner , T : TypeFoldable < I > , Ix : Idx > TypeFoldable < I > for IndexVec < Ix , T > {
163
203
fn try_fold_with < F : FallibleTypeFolder < I > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
164
- self . try_map_id ( |x| x . try_fold_with ( folder) )
204
+ self . raw . try_fold_with ( folder) . map ( IndexVec :: from_raw )
165
205
}
166
206
}
167
207
0 commit comments