22
33use rustc_data_structures:: fx:: FxHashSet ;
44use rustc_index:: bit_set:: BitSet ;
5+ use rustc_infer:: infer:: DefiningAnchor ;
56use rustc_infer:: infer:: TyCtxtInferExt ;
67use rustc_middle:: mir:: interpret:: Scalar ;
78use rustc_middle:: mir:: visit:: NonUseContext :: VarDebugInfo ;
@@ -11,13 +12,14 @@ use rustc_middle::mir::{
1112 MirPass , MirPhase , Operand , Place , PlaceElem , PlaceRef , ProjectionElem , RuntimePhase , Rvalue ,
1213 SourceScope , Statement , StatementKind , Terminator , TerminatorKind , UnOp , START_BLOCK ,
1314} ;
14- use rustc_middle:: ty :: fold :: BottomUpFolder ;
15+ use rustc_middle:: traits :: ObligationCause ;
1516use rustc_middle:: ty:: subst:: Subst ;
16- use rustc_middle:: ty:: { self , InstanceDef , ParamEnv , Ty , TyCtxt , TypeFoldable , TypeVisitable } ;
17+ use rustc_middle:: ty:: { self , InstanceDef , ParamEnv , Ty , TyCtxt , TypeVisitable } ;
1718use rustc_mir_dataflow:: impls:: MaybeStorageLive ;
1819use rustc_mir_dataflow:: storage:: always_storage_live_locals;
1920use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
2021use rustc_target:: abi:: { Size , VariantIdx } ;
22+ use rustc_trait_selection:: traits:: ObligationCtxt ;
2123
2224#[ derive( Copy , Clone , Debug ) ]
2325enum EdgeKind {
@@ -87,24 +89,36 @@ pub fn equal_up_to_regions<'tcx>(
8789 return true ;
8890 }
8991
90- // Normalize lifetimes away on both sides, then compare.
91- let normalize = |ty : Ty < ' tcx > | {
92- let ty = ty. fold_with ( & mut BottomUpFolder {
93- tcx,
94- // FIXME: We erase all late-bound lifetimes, but this is not fully correct.
95- // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`,
96- // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`,
97- // since one may have an `impl SomeTrait for fn(&32)` and
98- // `impl SomeTrait for fn(&'static u32)` at the same time which
99- // specify distinct values for Assoc. (See also #56105)
100- lt_op : |_| tcx. lifetimes . re_erased ,
101- // Leave consts and types unchanged.
102- ct_op : |ct| ct,
103- ty_op : |ty| ty,
104- } ) ;
105- tcx. try_normalize_erasing_regions ( param_env, ty) . unwrap_or ( ty)
106- } ;
107- tcx. infer_ctxt ( ) . enter ( |infcx| infcx. can_eq ( param_env, normalize ( src) , normalize ( dest) ) . is_ok ( ) )
92+ may_subtype_ignoring_regions ( tcx, param_env, src, dest)
93+ || may_subtype_ignoring_regions ( tcx, param_env, dest, src)
94+ }
95+
96+ fn may_subtype_ignoring_regions < ' tcx > (
97+ tcx : TyCtxt < ' tcx > ,
98+ param_env : ParamEnv < ' tcx > ,
99+ src : Ty < ' tcx > ,
100+ dest : Ty < ' tcx > ,
101+ ) -> bool {
102+ let mut builder =
103+ tcx. infer_ctxt ( ) . ignoring_regions ( ) . with_opaque_type_inference ( DefiningAnchor :: Bubble ) ;
104+ builder. enter ( |infcx| {
105+ let ocx = ObligationCtxt :: new ( & infcx) ;
106+ let cause = ObligationCause :: dummy ( ) ;
107+ let src = ocx. normalize ( cause. clone ( ) , param_env, src) ;
108+ let dest = ocx. normalize ( cause. clone ( ) , param_env, dest) ;
109+ let Ok ( infer_ok) = infcx. at ( & cause, param_env) . eq ( src, dest) else {
110+ return false ;
111+ } ;
112+ let ( ) = ocx. register_infer_ok_obligations ( infer_ok) ;
113+ let errors = ocx. select_all_or_error ( ) ;
114+ // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing`
115+ // we would get unification errors because we're unable to look into opaque types,
116+ // even if they're constrained in our current function.
117+ //
118+ // It seems very unlikely that this hides any bugs.
119+ let _ = infcx. inner . borrow_mut ( ) . opaque_type_storage . take_opaque_types ( ) ;
120+ errors. is_empty ( )
121+ } )
108122}
109123
110124struct TypeChecker < ' a , ' tcx > {
@@ -187,16 +201,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
187201 // all normal lifetimes are erased, higher-ranked types with their
188202 // late-bound lifetimes are still around and can lead to type
189203 // differences. So we compare ignoring lifetimes.
190-
191- // First, try with reveal_all. This might not work in some cases, as the predicates
192- // can be cleared in reveal_all mode. We try the reveal first anyways as it is used
193- // by some other passes like inlining as well.
194- let param_env = self . param_env . with_reveal_all_normalized ( self . tcx ) ;
195- if equal_up_to_regions ( self . tcx , param_env, src, dest) {
196- return true ;
197- }
198-
199- // If this fails, we can try it without the reveal.
200204 equal_up_to_regions ( self . tcx , self . param_env , src, dest)
201205 }
202206}
@@ -283,7 +287,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
283287 this. fail (
284288 location,
285289 format ! (
286- "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}" ,
290+ "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is ` {:?}` " ,
287291 parent, f, ty, f_ty
288292 )
289293 )
0 commit comments