@@ -2,13 +2,15 @@ use crate::check::regionck::RegionCtxt;
2
2
3
3
use crate :: hir;
4
4
use crate :: hir:: def_id:: DefId ;
5
+ use crate :: util:: common:: ErrorReported ;
5
6
use rustc:: infer:: outlives:: env:: OutlivesEnvironment ;
6
7
use rustc:: infer:: { InferOk , SuppressRegionErrors } ;
7
8
use rustc:: middle:: region;
8
9
use rustc:: traits:: { ObligationCause , TraitEngine , TraitEngineExt } ;
10
+ use rustc:: ty:: error:: TypeError ;
11
+ use rustc:: ty:: relate:: { Relate , RelateResult , TypeRelation } ;
9
12
use 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 } ;
12
14
13
15
use syntax_pos:: Span ;
14
16
@@ -192,6 +194,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
192
194
let assumptions_in_impl_context = generic_assumptions. instantiate ( tcx, & self_to_impl_substs) ;
193
195
let assumptions_in_impl_context = assumptions_in_impl_context. predicates ;
194
196
197
+ let self_param_env = tcx. param_env ( self_type_did) ;
198
+
195
199
// An earlier version of this code attempted to do this checking
196
200
// via the traits::fulfill machinery. However, it ran into trouble
197
201
// since the fulfill machinery merely turns outlives-predicates
@@ -205,14 +209,35 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
205
209
// to take on a structure that is roughly an alpha-renaming of
206
210
// the generic parameters of the item definition.)
207
211
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.
210
215
//
211
216
// 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
+ } ;
214
239
215
- if !assumptions_in_impl_context. contains ( & predicate ) {
240
+ if !assumptions_in_impl_context. iter ( ) . any ( predicate_matches_closure ) {
216
241
let item_span = tcx. hir ( ) . span ( self_type_hir_id) ;
217
242
struct_span_err ! (
218
243
tcx. sess,
@@ -251,3 +276,99 @@ crate fn check_drop_obligations<'a, 'tcx>(
251
276
252
277
Ok ( ( ) )
253
278
}
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