@@ -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
@@ -56,8 +58,10 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
56
58
// already checked by coherence, but compilation may
57
59
// not have been terminated.
58
60
let span = tcx. def_span ( drop_impl_did) ;
59
- tcx. sess . delay_span_bug ( span,
60
- & format ! ( "should have been rejected by coherence check: {}" , dtor_self_type) ) ;
61
+ tcx. sess . delay_span_bug (
62
+ span,
63
+ & format ! ( "should have been rejected by coherence check: {}" , dtor_self_type) ,
64
+ ) ;
61
65
Err ( ErrorReported )
62
66
}
63
67
}
@@ -85,10 +89,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
85
89
let fresh_impl_self_ty = drop_impl_ty. subst ( tcx, fresh_impl_substs) ;
86
90
87
91
let cause = & ObligationCause :: misc ( drop_impl_span, drop_impl_hir_id) ;
88
- match infcx
89
- . at ( cause, impl_param_env)
90
- . eq ( named_type, fresh_impl_self_ty)
91
- {
92
+ match infcx. at ( cause, impl_param_env) . eq ( named_type, fresh_impl_self_ty) {
92
93
Ok ( InferOk { obligations, .. } ) => {
93
94
fulfillment_cx. register_predicate_obligations ( infcx, obligations) ;
94
95
}
@@ -99,12 +100,13 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
99
100
drop_impl_span,
100
101
E0366 ,
101
102
"Implementations of Drop cannot be specialized"
102
- ) . span_note (
103
+ )
104
+ . span_note (
103
105
item_span,
104
106
"Use same sequence of generic type and region \
105
107
parameters that is on the struct/enum definition",
106
108
)
107
- . emit ( ) ;
109
+ . emit ( ) ;
108
110
return Err ( ErrorReported ) ;
109
111
}
110
112
}
@@ -194,6 +196,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
194
196
let assumptions_in_impl_context = generic_assumptions. instantiate ( tcx, & self_to_impl_substs) ;
195
197
let assumptions_in_impl_context = assumptions_in_impl_context. predicates ;
196
198
199
+ let self_param_env = tcx. param_env ( self_type_did) ;
200
+
197
201
// An earlier version of this code attempted to do this checking
198
202
// via the traits::fulfill machinery. However, it ran into trouble
199
203
// since the fulfill machinery merely turns outlives-predicates
@@ -207,27 +211,49 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
207
211
// to take on a structure that is roughly an alpha-renaming of
208
212
// the generic parameters of the item definition.)
209
213
210
- // This path now just checks *all* predicates via the direct
211
- // lookup, rather than using fulfill machinery.
214
+ // This path now just checks *all* predicates via an instantiation of
215
+ // the `SimpleEqRelation`, which simply forwards to the `relate` machinery
216
+ // after taking care of anonymizing late bound regions.
212
217
//
213
218
// However, it may be more efficient in the future to batch
214
- // the analysis together via the fulfill , rather than the
215
- // repeated `contains` calls.
219
+ // the analysis together via the fulfill (see comment above regarding
220
+ // the usage of the fulfill machinery), rather than the
221
+ // repeated `.iter().any(..)` calls.
216
222
217
- if !assumptions_in_impl_context. contains ( & predicate) {
223
+ // This closure is a more robust way to check `Predicate` equality
224
+ // than simple `==` checks (which were the previous implementation).
225
+ // It relies on `ty::relate` for `TraitPredicate` and `ProjectionPredicate`
226
+ // (which implement the Relate trait), while delegating on simple equality
227
+ // for the other `Predicate`.
228
+ // This implementation solves (Issue #59497) and (Issue #58311).
229
+ // It is unclear to me at the moment whether the approach based on `relate`
230
+ // could be extended easily also to the other `Predicate`.
231
+ let predicate_matches_closure = |p : & ' _ Predicate < ' tcx > | {
232
+ let mut relator: SimpleEqRelation < ' tcx > = SimpleEqRelation :: new ( tcx, self_param_env) ;
233
+ match ( predicate, p) {
234
+ ( Predicate :: Trait ( a) , Predicate :: Trait ( b) ) => relator. relate ( a, b) . is_ok ( ) ,
235
+ ( Predicate :: Projection ( a) , Predicate :: Projection ( b) ) => {
236
+ relator. relate ( a, b) . is_ok ( )
237
+ }
238
+ _ => predicate == p,
239
+ }
240
+ } ;
241
+
242
+ if !assumptions_in_impl_context. iter ( ) . any ( predicate_matches_closure) {
218
243
let item_span = tcx. hir ( ) . span ( self_type_hir_id) ;
219
244
struct_span_err ! (
220
245
tcx. sess,
221
246
drop_impl_span,
222
247
E0367 ,
223
248
"The requirement `{}` is added only by the Drop impl." ,
224
249
predicate
225
- ) . span_note (
250
+ )
251
+ . span_note (
226
252
item_span,
227
253
"The same requirement must be part of \
228
254
the struct/enum definition",
229
255
)
230
- . emit ( ) ;
256
+ . emit ( ) ;
231
257
result = Err ( ErrorReported ) ;
232
258
}
233
259
}
@@ -253,3 +279,99 @@ crate fn check_drop_obligations<'a, 'tcx>(
253
279
254
280
Ok ( ( ) )
255
281
}
282
+
283
+ // This is an implementation of the TypeRelation trait with the
284
+ // aim of simply comparing for equality (without side-effects).
285
+ // It is not intended to be used anywhere else other than here.
286
+ crate struct SimpleEqRelation < ' tcx > {
287
+ tcx : TyCtxt < ' tcx > ,
288
+ param_env : ty:: ParamEnv < ' tcx > ,
289
+ }
290
+
291
+ impl < ' tcx > SimpleEqRelation < ' tcx > {
292
+ fn new ( tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> SimpleEqRelation < ' tcx > {
293
+ SimpleEqRelation { tcx, param_env }
294
+ }
295
+ }
296
+
297
+ impl TypeRelation < ' tcx > for SimpleEqRelation < ' tcx > {
298
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
299
+ self . tcx
300
+ }
301
+
302
+ fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > {
303
+ self . param_env
304
+ }
305
+
306
+ fn tag ( & self ) -> & ' static str {
307
+ "dropck::SimpleEqRelation"
308
+ }
309
+
310
+ fn a_is_expected ( & self ) -> bool {
311
+ true
312
+ }
313
+
314
+ fn relate_with_variance < T : Relate < ' tcx > > (
315
+ & mut self ,
316
+ _: ty:: Variance ,
317
+ a : & T ,
318
+ b : & T ,
319
+ ) -> RelateResult < ' tcx , T > {
320
+ // Here we ignore variance because we require drop impl's types
321
+ // to be *exactly* the same as to the ones in the struct definition.
322
+ self . relate ( a, b)
323
+ }
324
+
325
+ fn tys ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
326
+ debug ! ( "SimpleEqRelation::tys(a={:?}, b={:?})" , a, b) ;
327
+ ty:: relate:: super_relate_tys ( self , a, b)
328
+ }
329
+
330
+ fn regions (
331
+ & mut self ,
332
+ a : ty:: Region < ' tcx > ,
333
+ b : ty:: Region < ' tcx > ,
334
+ ) -> RelateResult < ' tcx , ty:: Region < ' tcx > > {
335
+ debug ! ( "SimpleEqRelation::regions(a={:?}, b={:?})" , a, b) ;
336
+
337
+ // We can just equate the regions because LBRs have been
338
+ // already anonymized.
339
+ if a == b {
340
+ Ok ( a)
341
+ } else {
342
+ // I'm not sure is this `TypeError` is the right one, but
343
+ // it should not matter as it won't be checked (the dropck
344
+ // will emit its own, more informative and higher-level errors
345
+ // in case anything goes wrong).
346
+ Err ( TypeError :: RegionsPlaceholderMismatch )
347
+ }
348
+ }
349
+
350
+ fn consts (
351
+ & mut self ,
352
+ a : & ' tcx ty:: Const < ' tcx > ,
353
+ b : & ' tcx ty:: Const < ' tcx > ,
354
+ ) -> RelateResult < ' tcx , & ' tcx ty:: Const < ' tcx > > {
355
+ debug ! ( "SimpleEqRelation::consts(a={:?}, b={:?})" , a, b) ;
356
+ ty:: relate:: super_relate_consts ( self , a, b)
357
+ }
358
+
359
+ fn binders < T > (
360
+ & mut self ,
361
+ a : & ty:: Binder < T > ,
362
+ b : & ty:: Binder < T > ,
363
+ ) -> RelateResult < ' tcx , ty:: Binder < T > >
364
+ where
365
+ T : Relate < ' tcx > ,
366
+ {
367
+ debug ! ( "SimpleEqRelation::binders({:?}: {:?}" , a, b) ;
368
+
369
+ // Anonymizing the LBRs is necessary to solve (Issue #59497).
370
+ // After we do so, it should be totally fine to skip the binders.
371
+ let anon_a = self . tcx . anonymize_late_bound_regions ( a) ;
372
+ let anon_b = self . tcx . anonymize_late_bound_regions ( b) ;
373
+ self . relate ( anon_a. skip_binder ( ) , anon_b. skip_binder ( ) ) ?;
374
+
375
+ Ok ( a. clone ( ) )
376
+ }
377
+ }
0 commit comments