@@ -2,13 +2,15 @@ use crate::check::regionck::RegionCtxt;
22
33use crate :: hir;
44use crate :: hir:: def_id:: DefId ;
5+ use crate :: util:: common:: ErrorReported ;
56use rustc:: infer:: outlives:: env:: OutlivesEnvironment ;
67use rustc:: infer:: { InferOk , SuppressRegionErrors } ;
78use rustc:: middle:: region;
89use rustc:: traits:: { ObligationCause , TraitEngine , TraitEngineExt } ;
10+ use rustc:: ty:: error:: TypeError ;
11+ use rustc:: ty:: relate:: { Relate , RelateResult , TypeRelation } ;
912use rustc:: ty:: subst:: { Subst , SubstsRef } ;
10- use rustc:: ty:: { self , Ty , TyCtxt } ;
11- use crate :: util:: common:: ErrorReported ;
13+ use rustc:: ty:: { self , Predicate , Ty , TyCtxt } ;
1214
1315use syntax_pos:: Span ;
1416
@@ -192,6 +194,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
192194 let assumptions_in_impl_context = generic_assumptions. instantiate ( tcx, & self_to_impl_substs) ;
193195 let assumptions_in_impl_context = assumptions_in_impl_context. predicates ;
194196
197+ let self_param_env = tcx. param_env ( self_type_did) ;
198+
195199 // An earlier version of this code attempted to do this checking
196200 // via the traits::fulfill machinery. However, it ran into trouble
197201 // since the fulfill machinery merely turns outlives-predicates
@@ -205,14 +209,35 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
205209 // to take on a structure that is roughly an alpha-renaming of
206210 // the generic parameters of the item definition.)
207211
208- // This path now just checks *all* predicates via the direct
209- // lookup, rather than using fulfill machinery.
212+ // This path now just checks *all* predicates via an instantiation of
213+ // the `SimpleEqRelation`, which simply forwards to the `relate` machinery
214+ // after taking care of anonymizing late bound regions.
210215 //
211216 // However, it may be more efficient in the future to batch
212- // the analysis together via the fulfill , rather than the
213- // repeated `contains` calls.
217+ // the analysis together via the fulfill (see comment above regarding
218+ // the usage of the fulfill machinery), rather than the
219+ // repeated `.iter().any(..)` calls.
220+
221+ // This closure is a more robust way to check `Predicate` equality
222+ // than simple `==` checks (which were the previous implementation).
223+ // It relies on `ty::relate` for `TraitPredicate` and `ProjectionPredicate`
224+ // (which implement the Relate trait), while delegating on simple equality
225+ // for the other `Predicate`.
226+ // This implementation solves (Issue #59497) and (Issue #58311).
227+ // It is unclear to me at the moment whether the approach based on `relate`
228+ // could be extended easily also to the other `Predicate`.
229+ let predicate_matches_closure = |p : & ' _ Predicate < ' tcx > | {
230+ let mut relator: SimpleEqRelation < ' tcx > = SimpleEqRelation :: new ( tcx, self_param_env) ;
231+ match ( predicate, p) {
232+ ( Predicate :: Trait ( a) , Predicate :: Trait ( b) ) => relator. relate ( a, b) . is_ok ( ) ,
233+ ( Predicate :: Projection ( a) , Predicate :: Projection ( b) ) => {
234+ relator. relate ( a, b) . is_ok ( )
235+ }
236+ _ => predicate == p,
237+ }
238+ } ;
214239
215- if !assumptions_in_impl_context. contains ( & predicate ) {
240+ if !assumptions_in_impl_context. iter ( ) . any ( predicate_matches_closure ) {
216241 let item_span = tcx. hir ( ) . span ( self_type_hir_id) ;
217242 struct_span_err ! (
218243 tcx. sess,
@@ -251,3 +276,99 @@ crate fn check_drop_obligations<'a, 'tcx>(
251276
252277 Ok ( ( ) )
253278}
279+
280+ // This is an implementation of the TypeRelation trait with the
281+ // aim of simply comparing for equality (without side-effects).
282+ // It is not intended to be used anywhere else other than here.
283+ crate struct SimpleEqRelation < ' tcx > {
284+ tcx : TyCtxt < ' tcx > ,
285+ param_env : ty:: ParamEnv < ' tcx > ,
286+ }
287+
288+ impl < ' tcx > SimpleEqRelation < ' tcx > {
289+ fn new ( tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> SimpleEqRelation < ' tcx > {
290+ SimpleEqRelation { tcx, param_env }
291+ }
292+ }
293+
294+ impl TypeRelation < ' tcx > for SimpleEqRelation < ' tcx > {
295+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
296+ self . tcx
297+ }
298+
299+ fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > {
300+ self . param_env
301+ }
302+
303+ fn tag ( & self ) -> & ' static str {
304+ "dropck::SimpleEqRelation"
305+ }
306+
307+ fn a_is_expected ( & self ) -> bool {
308+ true
309+ }
310+
311+ fn relate_with_variance < T : Relate < ' tcx > > (
312+ & mut self ,
313+ _: ty:: Variance ,
314+ a : & T ,
315+ b : & T ,
316+ ) -> RelateResult < ' tcx , T > {
317+ // Here we ignore variance because we require drop impl's types
318+ // to be *exactly* the same as to the ones in the struct definition.
319+ self . relate ( a, b)
320+ }
321+
322+ fn tys ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
323+ debug ! ( "SimpleEqRelation::tys(a={:?}, b={:?})" , a, b) ;
324+ ty:: relate:: super_relate_tys ( self , a, b)
325+ }
326+
327+ fn regions (
328+ & mut self ,
329+ a : ty:: Region < ' tcx > ,
330+ b : ty:: Region < ' tcx > ,
331+ ) -> RelateResult < ' tcx , ty:: Region < ' tcx > > {
332+ debug ! ( "SimpleEqRelation::regions(a={:?}, b={:?})" , a, b) ;
333+
334+ // We can just equate the regions because LBRs have been
335+ // already anonymized.
336+ if a == b {
337+ Ok ( a)
338+ } else {
339+ // I'm not sure is this `TypeError` is the right one, but
340+ // it should not matter as it won't be checked (the dropck
341+ // will emit its own, more informative and higher-level errors
342+ // in case anything goes wrong).
343+ Err ( TypeError :: RegionsPlaceholderMismatch )
344+ }
345+ }
346+
347+ fn consts (
348+ & mut self ,
349+ a : & ' tcx ty:: Const < ' tcx > ,
350+ b : & ' tcx ty:: Const < ' tcx > ,
351+ ) -> RelateResult < ' tcx , & ' tcx ty:: Const < ' tcx > > {
352+ debug ! ( "SimpleEqRelation::consts(a={:?}, b={:?})" , a, b) ;
353+ ty:: relate:: super_relate_consts ( self , a, b)
354+ }
355+
356+ fn binders < T > (
357+ & mut self ,
358+ a : & ty:: Binder < T > ,
359+ b : & ty:: Binder < T > ,
360+ ) -> RelateResult < ' tcx , ty:: Binder < T > >
361+ where
362+ T : Relate < ' tcx > ,
363+ {
364+ debug ! ( "SimpleEqRelation::binders({:?}: {:?}" , a, b) ;
365+
366+ // Anonymizing the LBRs is necessary to solve (Issue #59497).
367+ // After we do so, it should be totally fine to skip the binders.
368+ let anon_a = self . tcx . anonymize_late_bound_regions ( a) ;
369+ let anon_b = self . tcx . anonymize_late_bound_regions ( b) ;
370+ self . relate ( anon_a. skip_binder ( ) , anon_b. skip_binder ( ) ) ?;
371+
372+ Ok ( a. clone ( ) )
373+ }
374+ }
0 commit comments