@@ -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
@@ -56,8 +58,10 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
5658 // already checked by coherence, but compilation may
5759 // not have been terminated.
5860 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+ ) ;
6165 Err ( ErrorReported )
6266 }
6367 }
@@ -85,10 +89,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
8589 let fresh_impl_self_ty = drop_impl_ty. subst ( tcx, fresh_impl_substs) ;
8690
8791 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) {
9293 Ok ( InferOk { obligations, .. } ) => {
9394 fulfillment_cx. register_predicate_obligations ( infcx, obligations) ;
9495 }
@@ -99,12 +100,13 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
99100 drop_impl_span,
100101 E0366 ,
101102 "Implementations of Drop cannot be specialized"
102- ) . span_note (
103+ )
104+ . span_note (
103105 item_span,
104106 "Use same sequence of generic type and region \
105107 parameters that is on the struct/enum definition",
106108 )
107- . emit ( ) ;
109+ . emit ( ) ;
108110 return Err ( ErrorReported ) ;
109111 }
110112 }
@@ -194,6 +196,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
194196 let assumptions_in_impl_context = generic_assumptions. instantiate ( tcx, & self_to_impl_substs) ;
195197 let assumptions_in_impl_context = assumptions_in_impl_context. predicates ;
196198
199+ let self_param_env = tcx. param_env ( self_type_did) ;
200+
197201 // An earlier version of this code attempted to do this checking
198202 // via the traits::fulfill machinery. However, it ran into trouble
199203 // since the fulfill machinery merely turns outlives-predicates
@@ -207,27 +211,49 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
207211 // to take on a structure that is roughly an alpha-renaming of
208212 // the generic parameters of the item definition.)
209213
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.
212217 //
213218 // 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.
216222
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) {
218243 let item_span = tcx. hir ( ) . span ( self_type_hir_id) ;
219244 struct_span_err ! (
220245 tcx. sess,
221246 drop_impl_span,
222247 E0367 ,
223248 "The requirement `{}` is added only by the Drop impl." ,
224249 predicate
225- ) . span_note (
250+ )
251+ . span_note (
226252 item_span,
227253 "The same requirement must be part of \
228254 the struct/enum definition",
229255 )
230- . emit ( ) ;
256+ . emit ( ) ;
231257 result = Err ( ErrorReported ) ;
232258 }
233259 }
@@ -253,3 +279,99 @@ crate fn check_drop_obligations<'a, 'tcx>(
253279
254280 Ok ( ( ) )
255281}
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