11// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`. 
22// 
33// We don't do any drop checking during hir typeck. 
4+ use  rustc_data_structures:: fx:: FxHashSet ; 
45use  rustc_errors:: { struct_span_err,  ErrorGuaranteed } ; 
5- use  rustc_middle :: ty :: error :: TypeError ; 
6- use  rustc_middle :: ty :: relate :: { Relate ,   RelateResult ,   TypeRelation } ; 
6+ use  rustc_infer :: infer :: outlives :: env :: OutlivesEnvironment ; 
7+ use  rustc_infer :: infer :: { RegionResolutionError ,   TyCtxtInferExt } ; 
78use  rustc_middle:: ty:: subst:: SubstsRef ; 
89use  rustc_middle:: ty:: util:: IgnoreRegions ; 
9- use  rustc_middle:: ty:: { self ,  Predicate ,  Ty ,  TyCtxt } ; 
10+ use  rustc_middle:: ty:: { self ,  TyCtxt } ; 
11+ use  rustc_trait_selection:: traits:: { self ,  ObligationCtxt } ; 
1012
1113use  crate :: errors; 
1214use  crate :: hir:: def_id:: { DefId ,  LocalDefId } ; 
@@ -43,21 +45,20 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
4345        } 
4446    } 
4547    let  dtor_self_type = tcx. type_of ( drop_impl_did) . subst_identity ( ) ; 
46-     let  dtor_predicates = tcx. predicates_of ( drop_impl_did) ; 
4748    match  dtor_self_type. kind ( )  { 
48-         ty:: Adt ( adt_def,  self_to_impl_substs )  => { 
49+         ty:: Adt ( adt_def,  adt_to_impl_substs )  => { 
4950            ensure_drop_params_and_item_params_correspond ( 
5051                tcx, 
5152                drop_impl_did. expect_local ( ) , 
5253                adt_def. did ( ) , 
53-                 self_to_impl_substs , 
54+                 adt_to_impl_substs , 
5455            ) ?; 
5556
5657            ensure_drop_predicates_are_implied_by_item_defn ( 
5758                tcx, 
58-                 dtor_predicates , 
59+                 drop_impl_did . expect_local ( ) , 
5960                adt_def. did ( ) . expect_local ( ) , 
60-                 self_to_impl_substs , 
61+                 adt_to_impl_substs , 
6162            ) 
6263        } 
6364        _ => { 
@@ -78,9 +79,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
7879    tcx :  TyCtxt < ' tcx > , 
7980    drop_impl_did :  LocalDefId , 
8081    self_type_did :  DefId , 
81-     drop_impl_substs :  SubstsRef < ' tcx > , 
82+     adt_to_impl_substs :  SubstsRef < ' tcx > , 
8283)  -> Result < ( ) ,  ErrorGuaranteed >  { 
83-     let  Err ( arg)  = tcx. uses_unique_generic_params ( drop_impl_substs ,  IgnoreRegions :: No )  else  { 
84+     let  Err ( arg)  = tcx. uses_unique_generic_params ( adt_to_impl_substs ,  IgnoreRegions :: No )  else  { 
8485        return  Ok ( ( ) ) 
8586    } ; 
8687
@@ -111,237 +112,94 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
111112/// implied by assuming the predicates attached to self_type_did. 
112113fn  ensure_drop_predicates_are_implied_by_item_defn < ' tcx > ( 
113114    tcx :  TyCtxt < ' tcx > , 
114-     dtor_predicates :  ty :: GenericPredicates < ' tcx > , 
115-     self_type_did :  LocalDefId , 
116-     self_to_impl_substs :  SubstsRef < ' tcx > , 
115+     drop_impl_def_id :   LocalDefId , 
116+     adt_def_id :  LocalDefId , 
117+     adt_to_impl_substs :  SubstsRef < ' tcx > , 
117118)  -> Result < ( ) ,  ErrorGuaranteed >  { 
118-     let  mut  result = Ok ( ( ) ) ; 
119- 
120-     // Here is an example, analogous to that from 
121-     // `compare_impl_method`. 
122-     // 
123-     // Consider a struct type: 
124-     // 
125-     //     struct Type<'c, 'b:'c, 'a> { 
126-     //         x: &'a Contents            // (contents are irrelevant; 
127-     //         y: &'c Cell<&'b Contents>, //  only the bounds matter for our purposes.) 
128-     //     } 
129-     // 
130-     // and a Drop impl: 
131-     // 
132-     //     impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> { 
133-     //         fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y) 
134-     //     } 
135-     // 
136-     // We start out with self_to_impl_substs, that maps the generic 
137-     // parameters of Type to that of the Drop impl. 
119+     let  infcx = tcx. infer_ctxt ( ) . build ( ) ; 
120+     let  ocx = ObligationCtxt :: new ( & infcx) ; 
121+ 
122+     // Take the param-env of the adt and substitute the substs that show up in 
123+     // the implementation's self type. This gives us the assumptions that the 
124+     // self ty of the implementation is allowed to know just from it being a 
125+     // well-formed adt, since that's all we're allowed to assume while proving 
126+     // the Drop implementation is not specialized. 
138127    // 
139-     //     self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x} 
140-     // 
141-     // Applying this to the predicates (i.e., assumptions) provided by the item 
142-     // definition yields the instantiated assumptions: 
143-     // 
144-     //     ['y : 'z] 
145-     // 
146-     // We then check all of the predicates of the Drop impl: 
147-     // 
148-     //     ['y:'z, 'x:'y] 
149-     // 
150-     // and ensure each is in the list of instantiated 
151-     // assumptions. Here, `'y:'z` is present, but `'x:'y` is 
152-     // absent. So we report an error that the Drop impl injected a 
153-     // predicate that is not present on the struct definition. 
154- 
155-     // We can assume the predicates attached to struct/enum definition 
156-     // hold. 
157-     let  generic_assumptions = tcx. predicates_of ( self_type_did) ; 
158- 
159-     let  assumptions_in_impl_context = generic_assumptions. instantiate ( tcx,  & self_to_impl_substs) ; 
160-     let  assumptions_in_impl_context = assumptions_in_impl_context. predicates ; 
161- 
162-     debug ! ( ?assumptions_in_impl_context,  ?dtor_predicates. predicates) ; 
163- 
164-     let  self_param_env = tcx. param_env ( self_type_did) ; 
165- 
166-     // An earlier version of this code attempted to do this checking 
167-     // via the traits::fulfill machinery. However, it ran into trouble 
168-     // since the fulfill machinery merely turns outlives-predicates 
169-     // 'a:'b and T:'b into region inference constraints. It is simpler 
170-     // just to look for all the predicates directly. 
171- 
172-     assert_eq ! ( dtor_predicates. parent,  None ) ; 
173-     for  & ( predicate,  predicate_sp)  in  dtor_predicates. predicates  { 
174-         // (We do not need to worry about deep analysis of type 
175-         // expressions etc because the Drop impls are already forced 
176-         // to take on a structure that is roughly an alpha-renaming of 
177-         // the generic parameters of the item definition.) 
178- 
179-         // This path now just checks *all* predicates via an instantiation of 
180-         // the `SimpleEqRelation`, which simply forwards to the `relate` machinery 
181-         // after taking care of anonymizing late bound regions. 
182-         // 
183-         // However, it may be more efficient in the future to batch 
184-         // the analysis together via the fulfill (see comment above regarding 
185-         // the usage of the fulfill machinery), rather than the 
186-         // repeated `.iter().any(..)` calls. 
128+     // We don't need to normalize this param-env or anything, since we're only 
129+     // substituting it with free params, so no additional param-env normalization 
130+     // can occur on top of what has been done in the param_env query itself. 
131+     let  param_env = ty:: EarlyBinder ( tcx. param_env ( adt_def_id) ) 
132+         . subst ( tcx,  adt_to_impl_substs) 
133+         . with_constness ( tcx. constness ( drop_impl_def_id) ) ; 
134+ 
135+     for  ( pred,  span)  in  tcx. predicates_of ( drop_impl_def_id) . instantiate_identity ( tcx)  { 
136+         let  normalize_cause = traits:: ObligationCause :: misc ( span,  adt_def_id) ; 
137+         let  pred = ocx. normalize ( & normalize_cause,  param_env,  pred) ; 
138+         let  cause = traits:: ObligationCause :: new ( span,  adt_def_id,  traits:: DropImpl ) ; 
139+         ocx. register_obligation ( traits:: Obligation :: new ( tcx,  cause,  param_env,  pred) ) ; 
140+     } 
187141
188-         // This closure is a more robust way to check `Predicate` equality 
189-         // than simple `==` checks (which were the previous implementation). 
190-         // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`, 
191-         // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait), 
192-         // while delegating on simple equality for the other `Predicate`. 
193-         // This implementation solves (Issue #59497) and (Issue #58311). 
194-         // It is unclear to me at the moment whether the approach based on `relate` 
195-         // could be extended easily also to the other `Predicate`. 
196-         let  predicate_matches_closure = |p :  Predicate < ' tcx > | { 
197-             let  mut  relator:  SimpleEqRelation < ' tcx >  = SimpleEqRelation :: new ( tcx,  self_param_env) ; 
198-             let  predicate = predicate. kind ( ) ; 
199-             let  p = p. kind ( ) ; 
200-             match  ( predicate. skip_binder ( ) ,  p. skip_binder ( ) )  { 
201-                 ( 
202-                     ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( a) ) , 
203-                     ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( b) ) , 
204-                 )  => relator. relate ( predicate. rebind ( a) ,  p. rebind ( b) ) . is_ok ( ) , 
205-                 ( 
206-                     ty:: PredicateKind :: Clause ( ty:: Clause :: Projection ( a) ) , 
207-                     ty:: PredicateKind :: Clause ( ty:: Clause :: Projection ( b) ) , 
208-                 )  => relator. relate ( predicate. rebind ( a) ,  p. rebind ( b) ) . is_ok ( ) , 
209-                 ( 
210-                     ty:: PredicateKind :: ConstEvaluatable ( a) , 
211-                     ty:: PredicateKind :: ConstEvaluatable ( b) , 
212-                 )  => relator. relate ( predicate. rebind ( a) ,  predicate. rebind ( b) ) . is_ok ( ) , 
213-                 ( 
214-                     ty:: PredicateKind :: Clause ( ty:: Clause :: TypeOutlives ( ty:: OutlivesPredicate ( 
215-                         ty_a, 
216-                         lt_a, 
217-                     ) ) ) , 
218-                     ty:: PredicateKind :: Clause ( ty:: Clause :: TypeOutlives ( ty:: OutlivesPredicate ( 
219-                         ty_b, 
220-                         lt_b, 
221-                     ) ) ) , 
222-                 )  => { 
223-                     relator. relate ( predicate. rebind ( ty_a) ,  p. rebind ( ty_b) ) . is_ok ( ) 
224-                         && relator. relate ( predicate. rebind ( lt_a) ,  p. rebind ( lt_b) ) . is_ok ( ) 
225-                 } 
226-                 ( ty:: PredicateKind :: WellFormed ( arg_a) ,  ty:: PredicateKind :: WellFormed ( arg_b) )  => { 
227-                     relator. relate ( predicate. rebind ( arg_a) ,  p. rebind ( arg_b) ) . is_ok ( ) 
228-                 } 
229-                 _ => predicate == p, 
142+     // All of the custom error reporting logic is to preserve parity with the old 
143+     // error messages. 
144+     // 
145+     // They can probably get removed with better treatment of the new `DropImpl` 
146+     // obligation cause code, and perhaps some custom logic in `report_region_errors`. 
147+ 
148+     let  errors = ocx. select_all_or_error ( ) ; 
149+     if  !errors. is_empty ( )  { 
150+         let  mut  guar = None ; 
151+         let  mut  root_predicates = FxHashSet :: default ( ) ; 
152+         for  error in  errors { 
153+             let  root_predicate = error. root_obligation . predicate ; 
154+             if  root_predicates. insert ( root_predicate)  { 
155+                 let  item_span = tcx. def_span ( adt_def_id) ; 
156+                 let  self_descr = tcx. def_descr ( adt_def_id. to_def_id ( ) ) ; 
157+                 guar = Some ( 
158+                     struct_span_err ! ( 
159+                         tcx. sess, 
160+                         error. root_obligation. cause. span, 
161+                         E0367 , 
162+                         "`Drop` impl requires `{root_predicate}` \  
163+ , 
164+                     ) 
165+                     . span_note ( item_span,  "the implementor must specify the same requirement" ) 
166+                     . emit ( ) , 
167+                 ) ; 
230168            } 
231-         } ; 
232- 
233-         if  !assumptions_in_impl_context. iter ( ) . copied ( ) . any ( predicate_matches_closure)  { 
234-             let  item_span = tcx. def_span ( self_type_did) ; 
235-             let  self_descr = tcx. def_descr ( self_type_did. to_def_id ( ) ) ; 
236-             let  reported = struct_span_err ! ( 
237-                 tcx. sess, 
238-                 predicate_sp, 
239-                 E0367 , 
240-                 "`Drop` impl requires `{predicate}` but the {self_descr} it is implemented for does not" , 
241-             ) 
242-             . span_note ( item_span,  "the implementor must specify the same requirement" ) 
243-             . emit ( ) ; 
244-             result = Err ( reported) ; 
245169        } 
170+         return  Err ( guar. unwrap ( ) ) ; 
246171    } 
247172
248-     result
249- } 
250- 
251- /// This is an implementation of the [`TypeRelation`] trait with the 
252- /// aim of simply comparing for equality (without side-effects). 
253- /// 
254- /// It is not intended to be used anywhere else other than here. 
255- pub ( crate )  struct  SimpleEqRelation < ' tcx >  { 
256-     tcx :  TyCtxt < ' tcx > , 
257-     param_env :  ty:: ParamEnv < ' tcx > , 
258- } 
259- 
260- impl < ' tcx >  SimpleEqRelation < ' tcx >  { 
261-     fn  new ( tcx :  TyCtxt < ' tcx > ,  param_env :  ty:: ParamEnv < ' tcx > )  -> SimpleEqRelation < ' tcx >  { 
262-         SimpleEqRelation  {  tcx,  param_env } 
263-     } 
264- } 
265- 
266- impl < ' tcx >  TypeRelation < ' tcx >  for  SimpleEqRelation < ' tcx >  { 
267-     fn  tcx ( & self )  -> TyCtxt < ' tcx >  { 
268-         self . tcx 
269-     } 
270- 
271-     fn  param_env ( & self )  -> ty:: ParamEnv < ' tcx >  { 
272-         self . param_env 
273-     } 
274- 
275-     fn  tag ( & self )  -> & ' static  str  { 
276-         "dropck::SimpleEqRelation" 
277-     } 
278- 
279-     fn  a_is_expected ( & self )  -> bool  { 
280-         true 
281-     } 
282- 
283-     fn  relate_with_variance < T :  Relate < ' tcx > > ( 
284-         & mut  self , 
285-         _:  ty:: Variance , 
286-         _info :  ty:: VarianceDiagInfo < ' tcx > , 
287-         a :  T , 
288-         b :  T , 
289-     )  -> RelateResult < ' tcx ,  T >  { 
290-         // Here we ignore variance because we require drop impl's types 
291-         // to be *exactly* the same as to the ones in the struct definition. 
292-         self . relate ( a,  b) 
293-     } 
294- 
295-     fn  tys ( & mut  self ,  a :  Ty < ' tcx > ,  b :  Ty < ' tcx > )  -> RelateResult < ' tcx ,  Ty < ' tcx > >  { 
296-         debug ! ( "SimpleEqRelation::tys(a={:?}, b={:?})" ,  a,  b) ; 
297-         ty:: relate:: super_relate_tys ( self ,  a,  b) 
298-     } 
299- 
300-     fn  regions ( 
301-         & mut  self , 
302-         a :  ty:: Region < ' tcx > , 
303-         b :  ty:: Region < ' tcx > , 
304-     )  -> RelateResult < ' tcx ,  ty:: Region < ' tcx > >  { 
305-         debug ! ( "SimpleEqRelation::regions(a={:?}, b={:?})" ,  a,  b) ; 
306- 
307-         // We can just equate the regions because LBRs have been 
308-         // already anonymized. 
309-         if  a == b { 
310-             Ok ( a) 
311-         }  else  { 
312-             // I'm not sure is this `TypeError` is the right one, but 
313-             // it should not matter as it won't be checked (the dropck 
314-             // will emit its own, more informative and higher-level errors 
315-             // in case anything goes wrong). 
316-             Err ( TypeError :: RegionsPlaceholderMismatch ) 
173+     let  errors = ocx. infcx . resolve_regions ( & OutlivesEnvironment :: new ( param_env) ) ; 
174+     if  !errors. is_empty ( )  { 
175+         let  mut  guar = None ; 
176+         for  error in  errors { 
177+             let  item_span = tcx. def_span ( adt_def_id) ; 
178+             let  self_descr = tcx. def_descr ( adt_def_id. to_def_id ( ) ) ; 
179+             let  outlives = match  error { 
180+                 RegionResolutionError :: ConcreteFailure ( _,  a,  b)  => format ! ( "{b}: {a}" ) , 
181+                 RegionResolutionError :: GenericBoundFailure ( _,  generic,  r)  => { 
182+                     format ! ( "{generic}: {r}" ) 
183+                 } 
184+                 RegionResolutionError :: SubSupConflict ( _,  _,  _,  a,  _,  b,  _)  => format ! ( "{b}: {a}" ) , 
185+                 RegionResolutionError :: UpperBoundUniverseConflict ( a,  _,  _,  _,  b)  => { 
186+                     format ! ( "{b}: {a}" ,  a = tcx. mk_re_var( a) ) 
187+                 } 
188+             } ; 
189+             guar = Some ( 
190+                 struct_span_err ! ( 
191+                     tcx. sess, 
192+                     error. origin( ) . span( ) , 
193+                     E0367 , 
194+                     "`Drop` impl requires `{outlives}` \  
195+ , 
196+                 ) 
197+                 . span_note ( item_span,  "the implementor must specify the same requirement" ) 
198+                 . emit ( ) , 
199+             ) ; 
317200        } 
201+         return  Err ( guar. unwrap ( ) ) ; 
318202    } 
319203
320-     fn  consts ( 
321-         & mut  self , 
322-         a :  ty:: Const < ' tcx > , 
323-         b :  ty:: Const < ' tcx > , 
324-     )  -> RelateResult < ' tcx ,  ty:: Const < ' tcx > >  { 
325-         debug ! ( "SimpleEqRelation::consts(a={:?}, b={:?})" ,  a,  b) ; 
326-         ty:: relate:: super_relate_consts ( self ,  a,  b) 
327-     } 
328- 
329-     fn  binders < T > ( 
330-         & mut  self , 
331-         a :  ty:: Binder < ' tcx ,  T > , 
332-         b :  ty:: Binder < ' tcx ,  T > , 
333-     )  -> RelateResult < ' tcx ,  ty:: Binder < ' tcx ,  T > > 
334-     where 
335-         T :  Relate < ' tcx > , 
336-     { 
337-         debug ! ( "SimpleEqRelation::binders({:?}: {:?}" ,  a,  b) ; 
338- 
339-         // Anonymizing the LBRs is necessary to solve (Issue #59497). 
340-         // After we do so, it should be totally fine to skip the binders. 
341-         let  anon_a = self . tcx . anonymize_bound_vars ( a) ; 
342-         let  anon_b = self . tcx . anonymize_bound_vars ( b) ; 
343-         self . relate ( anon_a. skip_binder ( ) ,  anon_b. skip_binder ( ) ) ?; 
344- 
345-         Ok ( a) 
346-     } 
204+     Ok ( ( ) ) 
347205} 
0 commit comments