@@ -17,7 +17,8 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
1717 // needs drop.
1818 let adt_has_dtor =
1919 |adt_def : & ty:: AdtDef | adt_def. destructor ( tcx) . map ( |_| DtorType :: Significant ) ;
20- let res = drop_tys_helper ( tcx, query. value , query. param_env , adt_has_dtor) . next ( ) . is_some ( ) ;
20+ let res =
21+ drop_tys_helper ( tcx, query. value , query. param_env , adt_has_dtor, false ) . next ( ) . is_some ( ) ;
2122
2223 debug ! ( "needs_drop_raw({:?}) = {:?}" , query, res) ;
2324 res
@@ -27,10 +28,15 @@ fn has_significant_drop_raw<'tcx>(
2728 tcx : TyCtxt < ' tcx > ,
2829 query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
2930) -> bool {
30- let res =
31- drop_tys_helper ( tcx, query. value , query. param_env , adt_consider_insignificant_dtor ( tcx) )
32- . next ( )
33- . is_some ( ) ;
31+ let res = drop_tys_helper (
32+ tcx,
33+ query. value ,
34+ query. param_env ,
35+ adt_consider_insignificant_dtor ( tcx) ,
36+ true ,
37+ )
38+ . next ( )
39+ . is_some ( ) ;
3440 debug ! ( "has_significant_drop_raw({:?}) = {:?}" , query, res) ;
3541 res
3642}
@@ -141,9 +147,9 @@ where
141147 Ok ( tys) => tys,
142148 } ;
143149 for required_ty in tys {
144- let subst_ty =
150+ let required =
145151 tcx. normalize_erasing_regions ( self . param_env , required_ty) ;
146- queue_type ( self , subst_ty ) ;
152+ queue_type ( self , required ) ;
147153 }
148154 }
149155 ty:: Array ( ..) | ty:: Opaque ( ..) | ty:: Projection ( ..) | ty:: Param ( _) => {
@@ -186,39 +192,67 @@ fn drop_tys_helper<'tcx>(
186192 ty : Ty < ' tcx > ,
187193 param_env : rustc_middle:: ty:: ParamEnv < ' tcx > ,
188194 adt_has_dtor : impl Fn ( & ty:: AdtDef ) -> Option < DtorType > ,
195+ only_significant : bool ,
189196) -> impl Iterator < Item = NeedsDropResult < Ty < ' tcx > > > {
197+ fn with_query_cache < ' tcx > (
198+ tcx : TyCtxt < ' tcx > ,
199+ iter : impl IntoIterator < Item = Ty < ' tcx > > ,
200+ only_significant : bool ,
201+ ) -> NeedsDropResult < Vec < Ty < ' tcx > > > {
202+ iter. into_iter ( ) . try_fold ( Vec :: new ( ) , |mut vec, subty| {
203+ match subty. kind ( ) {
204+ ty:: Adt ( adt_id, subst) => {
205+ for subty in if only_significant {
206+ tcx. adt_significant_drop_tys ( adt_id. did ) ?
207+ } else {
208+ tcx. adt_drop_tys ( adt_id. did ) ?
209+ } {
210+ vec. push ( subty. subst ( tcx, subst) ) ;
211+ }
212+ }
213+ _ => vec. push ( subty) ,
214+ } ;
215+ Ok ( vec)
216+ } )
217+ }
218+
190219 let adt_components = move |adt_def : & ty:: AdtDef , substs : SubstsRef < ' tcx > | {
191220 if adt_def. is_manually_drop ( ) {
192221 debug ! ( "drop_tys_helper: `{:?}` is manually drop" , adt_def) ;
193- return Ok ( Vec :: new ( ) . into_iter ( ) ) ;
222+ Ok ( Vec :: new ( ) )
194223 } else if let Some ( dtor_info) = adt_has_dtor ( adt_def) {
195224 match dtor_info {
196225 DtorType :: Significant => {
197226 debug ! ( "drop_tys_helper: `{:?}` implements `Drop`" , adt_def) ;
198- return Err ( AlwaysRequiresDrop ) ;
227+ Err ( AlwaysRequiresDrop )
199228 }
200229 DtorType :: Insignificant => {
201230 debug ! ( "drop_tys_helper: `{:?}` drop is insignificant" , adt_def) ;
202231
203232 // Since the destructor is insignificant, we just want to make sure all of
204233 // the passed in type parameters are also insignificant.
205234 // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
206- return Ok ( substs. types ( ) . collect :: < Vec < Ty < ' _ > > > ( ) . into_iter ( ) ) ;
235+ with_query_cache ( tcx , substs. types ( ) , only_significant )
207236 }
208237 }
209238 } else if adt_def. is_union ( ) {
210239 debug ! ( "drop_tys_helper: `{:?}` is a union" , adt_def) ;
211- return Ok ( Vec :: new ( ) . into_iter ( ) ) ;
240+ Ok ( Vec :: new ( ) )
241+ } else {
242+ with_query_cache (
243+ tcx,
244+ adt_def. all_fields ( ) . map ( |field| {
245+ let r = tcx. type_of ( field. did ) . subst ( tcx, substs) ;
246+ debug ! (
247+ "drop_tys_helper: Subst into {:?} with {:?} gettng {:?}" ,
248+ field, substs, r
249+ ) ;
250+ r
251+ } ) ,
252+ only_significant,
253+ )
212254 }
213- Ok ( adt_def
214- . all_fields ( )
215- . map ( |field| {
216- let r = tcx. type_of ( field. did ) . subst ( tcx, substs) ;
217- debug ! ( "drop_tys_helper: Subst into {:?} with {:?} gettng {:?}" , field, substs, r) ;
218- r
219- } )
220- . collect :: < Vec < _ > > ( )
221- . into_iter ( ) )
255+ . map ( |v| v. into_iter ( ) )
222256 } ;
223257
224258 NeedsDropTypes :: new ( tcx, param_env, ty, adt_components)
@@ -252,20 +286,24 @@ fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, Alw
252286 // significant.
253287 let adt_has_dtor =
254288 |adt_def : & ty:: AdtDef | adt_def. destructor ( tcx) . map ( |_| DtorType :: Significant ) ;
255- drop_tys_helper ( tcx, tcx. type_of ( def_id) , tcx. param_env ( def_id) , adt_has_dtor)
289+ // `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_substs)`
290+ drop_tys_helper ( tcx, tcx. type_of ( def_id) , tcx. param_env ( def_id) , adt_has_dtor, false )
256291 . collect :: < Result < Vec < _ > , _ > > ( )
257292 . map ( |components| tcx. intern_type_list ( & components) )
258293}
259-
294+ // If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed
295+ // a `tcx.make_ty(def, identity_substs)` and as such it is legal to substitue the generic parameters
296+ // of the ADT into the outputted `ty`s.
260297fn adt_significant_drop_tys (
261298 tcx : TyCtxt < ' _ > ,
262299 def_id : DefId ,
263300) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
264301 drop_tys_helper (
265302 tcx,
266- tcx. type_of ( def_id) ,
303+ tcx. type_of ( def_id) , // identical to `tcx.make_adt(def, identity_substs)`
267304 tcx. param_env ( def_id) ,
268305 adt_consider_insignificant_dtor ( tcx) ,
306+ true ,
269307 )
270308 . collect :: < Result < Vec < _ > , _ > > ( )
271309 . map ( |components| tcx. intern_type_list ( & components) )
0 commit comments