@@ -12,6 +12,7 @@ use rustc_middle::query::TyCtxtAt;
12
12
use rustc_middle:: ty:: layout:: {
13
13
self , FnAbiError , FnAbiOfHelpers , FnAbiRequest , LayoutError , LayoutOfHelpers , TyAndLayout ,
14
14
} ;
15
+ use rustc_middle:: ty:: relate:: Relate ;
15
16
use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypeFoldable , TypingEnv , Variance } ;
16
17
use rustc_middle:: { mir, span_bug} ;
17
18
use rustc_session:: Limit ;
@@ -323,12 +324,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
323
324
}
324
325
}
325
326
326
- /// Check if the two things are equal in the current param_env, using an infcx to get proper
327
- /// equality checks.
327
+ /// Check whether there is a subtyping relation between two things in either direction.
328
+ ///
329
+ /// This is called on [`ty::PolyExistentialTraitRef`] or [`ty::PolyExistentialProjection`]
330
+ /// to check whether the predicates of two trait objects are sufficiently equal to allow
331
+ /// transmutes between them.
332
+ ///
333
+ /// # Examples
334
+ ///
335
+ /// - returns `true` for `dyn for<'a> Trait<fn(&'a u8)>` and `dyn Trait<fn(&'static u8)>`
336
+ /// - returns `false` for `dyn Trait<for<'a> fn(&'a u8)>` and either of the above
328
337
#[ instrument( level = "trace" , skip( self ) , ret) ]
329
- pub ( super ) fn eq_in_param_env < T > ( & self , a : T , b : T ) -> bool
338
+ pub ( super ) fn relate_bivariantly < T > (
339
+ & self ,
340
+ a : ty:: Binder < ' tcx , T > ,
341
+ b : ty:: Binder < ' tcx , T > ,
342
+ ) -> bool
330
343
where
331
- T : PartialEq + TypeFoldable < TyCtxt < ' tcx > > + ToTrace < ' tcx > ,
344
+ T : PartialEq + Copy + TypeFoldable < TyCtxt < ' tcx > > + Relate < TyCtxt < ' tcx > > ,
345
+ ty:: Binder < ' tcx , T > : ToTrace < ' tcx > ,
332
346
{
333
347
// Fast path: compare directly.
334
348
if a == b {
@@ -338,11 +352,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
338
352
let ( infcx, param_env) = self . tcx . infer_ctxt ( ) . build_with_typing_env ( self . typing_env ) ;
339
353
let ocx = ObligationCtxt :: new ( & infcx) ;
340
354
let cause = ObligationCause :: dummy_with_span ( self . cur_span ( ) ) ;
355
+ let trace = ToTrace :: to_trace ( & cause, a, b) ;
356
+
357
+ // Instantiate the binder with erased instead of fresh vars, because in MIR
358
+ // all free regions are erased anyway, so it doesn't make a difference.
359
+ let a = self . tcx . instantiate_bound_regions_with_erased ( a) ;
360
+ let b = self . tcx . instantiate_bound_regions_with_erased ( b) ;
361
+
341
362
// equate the two trait refs after normalization
342
363
let a = ocx. normalize ( & cause, param_env, a) ;
343
364
let b = ocx. normalize ( & cause, param_env, b) ;
344
365
345
- if let Err ( terr) = ocx. eq ( & cause, param_env, a, b) {
366
+ if let Err ( terr) = ocx. eq_trace ( & cause, param_env, trace , a, b) {
346
367
trace ! ( ?terr) ;
347
368
return false ;
348
369
}
@@ -353,6 +374,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
353
374
return false ;
354
375
}
355
376
377
+ // Do a leak check to ensure that e.g. `for<'a> fn(&'a u8)` and `fn(&'static u8)` are not equal.
378
+ if let Err ( terr) = infcx. leak_check ( ty:: UniverseIndex :: ROOT , None ) {
379
+ trace ! ( ?terr, "failed leak check" ) ;
380
+ return false ;
381
+ }
382
+
356
383
// All good.
357
384
true
358
385
}
0 commit comments