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
@@ -120,8 +151,9 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Lrc<T> {
120
151
}
121
152
122
153
impl < I : Interner , T : TypeFoldable < I > > TypeFoldable < I > for Box < T > {
123
- 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) )
154
+ fn try_fold_with < F : FallibleTypeFolder < I > > ( mut self , folder : & mut F ) -> Result < Self , F :: Error > {
155
+ * self = ( * self ) . try_fold_with ( folder) ?;
156
+ Ok ( self )
125
157
}
126
158
}
127
159
@@ -133,7 +165,7 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> {
133
165
134
166
impl < I : Interner , T : TypeFoldable < I > > TypeFoldable < I > for Vec < T > {
135
167
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) )
168
+ self . into_iter ( ) . map ( |t| t. try_fold_with ( folder) ) . collect ( )
137
169
}
138
170
}
139
171
@@ -161,7 +193,7 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
161
193
162
194
impl < I : Interner , T : TypeFoldable < I > , Ix : Idx > TypeFoldable < I > for IndexVec < Ix , T > {
163
195
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) )
196
+ self . raw . try_fold_with ( folder) . map ( IndexVec :: from_raw )
165
197
}
166
198
}
167
199
0 commit comments