@@ -113,6 +113,11 @@ fn success<'tcx>(
113113 Ok ( InferOk { value : ( adj, target) , obligations } )
114114}
115115
116+ enum LeakCheck {
117+ Yes ,
118+ Default ,
119+ }
120+
116121impl < ' f , ' tcx > Coerce < ' f , ' tcx > {
117122 fn new (
118123 fcx : & ' f FnCtxt < ' f , ' tcx > ,
@@ -123,9 +128,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
123128 Coerce { fcx, cause, allow_two_phase, use_lub : false , coerce_never }
124129 }
125130
126- fn unify_raw ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> InferResult < ' tcx , Ty < ' tcx > > {
131+ fn unify_raw (
132+ & self ,
133+ a : Ty < ' tcx > ,
134+ b : Ty < ' tcx > ,
135+ leak_check : LeakCheck ,
136+ ) -> InferResult < ' tcx , Ty < ' tcx > > {
127137 debug ! ( "unify(a: {:?}, b: {:?}, use_lub: {})" , a, b, self . use_lub) ;
128- self . commit_if_ok ( |_| {
138+ self . commit_if_ok ( |snapshot| {
139+ let outer_universe = self . infcx . universe ( ) ;
140+
129141 let at = self . at ( & self . cause , self . fcx . param_env ) ;
130142
131143 let res = if self . use_lub {
@@ -138,7 +150,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
138150 // In the new solver, lazy norm may allow us to shallowly equate
139151 // more types, but we emit possibly impossible-to-satisfy obligations.
140152 // Filter these cases out to make sure our coercion is more accurate.
141- match res {
153+ let res = match res {
142154 Ok ( InferOk { value, obligations } ) if self . next_trait_solver ( ) => {
143155 let ocx = ObligationCtxt :: new ( self ) ;
144156 ocx. register_obligations ( obligations) ;
@@ -149,13 +161,35 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
149161 }
150162 }
151163 res => res,
164+ } ;
165+
166+ // We leak check here mostly because lub operations are
167+ // kind of scuffed around binders. Instead of computing an actual
168+ // lub'd binder we instead:
169+ // - Equate the binders
170+ // - Return the lhs of the lub operation
171+ //
172+ // This may lead to incomplete type inference for the resulting type
173+ // of a `match` or `if .. else`, etc. This is a backwards compat
174+ // hazard for if/when we start handling `lub` more correctly.
175+ //
176+ // In order to actually ensure that equating the binders *does*
177+ // result in equal binders, and that the lhs is actually a supertype
178+ // of the rhs, we must perform a leak check here.
179+ //
180+ // FIXME: Type relations should handle leak checks
181+ // themselves whenever a binder is entered.
182+ if matches ! ( leak_check, LeakCheck :: Yes ) {
183+ self . leak_check ( outer_universe, Some ( snapshot) ) ?;
152184 }
185+
186+ res
153187 } )
154188 }
155189
156190 /// Unify two types (using sub or lub).
157- fn unify ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
158- self . unify_raw ( a, b)
191+ fn unify ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > , leak_check : LeakCheck ) -> CoerceResult < ' tcx > {
192+ self . unify_raw ( a, b, leak_check )
159193 . and_then ( |InferOk { value : ty, obligations } | success ( vec ! [ ] , ty, obligations) )
160194 }
161195
@@ -166,8 +200,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
166200 b : Ty < ' tcx > ,
167201 adjustments : impl IntoIterator < Item = Adjustment < ' tcx > > ,
168202 final_adjustment : Adjust ,
203+ leak_check : LeakCheck ,
169204 ) -> CoerceResult < ' tcx > {
170- self . unify_raw ( a, b) . and_then ( |InferOk { value : ty, obligations } | {
205+ self . unify_raw ( a, b, leak_check ) . and_then ( |InferOk { value : ty, obligations } | {
171206 success (
172207 adjustments
173208 . into_iter ( )
@@ -196,7 +231,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
196231 ) ;
197232 } else {
198233 // Otherwise the only coercion we can do is unification.
199- return self . unify ( a, b) ;
234+ return self . unify ( a, b, LeakCheck :: Default ) ;
200235 }
201236 }
202237
@@ -266,7 +301,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
266301 }
267302 _ => {
268303 // Otherwise, just use unification rules.
269- self . unify ( a, b)
304+ self . unify ( a, b, LeakCheck :: Default )
270305 }
271306 }
272307 }
@@ -305,7 +340,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
305340 } else {
306341 // One unresolved type variable: just apply subtyping, we may be able
307342 // to do something useful.
308- self . unify ( a, b)
343+ self . unify ( a, b, LeakCheck :: Default )
309344 }
310345 }
311346
@@ -332,7 +367,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
332367 coerce_mutbls ( mutbl, mutbl_b) ?;
333368 ( r_a, ty:: TypeAndMut { ty, mutbl } )
334369 }
335- _ => return self . unify ( a, b) ,
370+ _ => return self . unify ( a, b, LeakCheck :: Default ) ,
336371 } ;
337372
338373 // Look at each step in the `Deref` chain and check if
@@ -383,7 +418,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
383418 // the `Target` type with the pointee of `b`. This is necessary
384419 // to properly account for the differing variances of the pointees
385420 // of `&` vs `&mut` references.
386- match self . unify_raw ( autorefd_deref_ty, b) {
421+ match self . unify_raw ( autorefd_deref_ty, b, LeakCheck :: Default ) {
387422 Ok ( ok) => Some ( ok) ,
388423 Err ( err) => {
389424 if first_error. is_none ( ) {
@@ -580,6 +615,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
580615 target,
581616 reborrow. into_iter ( ) . flat_map ( |( deref, autoref) | [ deref, autoref] ) ,
582617 Adjust :: Pointer ( PointerCoercion :: Unsize ) ,
618+ LeakCheck :: Default ,
583619 ) ?;
584620
585621 // Create an obligation for `Source: CoerceUnsized<Target>`.
@@ -794,7 +830,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
794830
795831 // To complete the reborrow, we need to make sure we can unify the inner types, and if so we
796832 // add the adjustments.
797- self . unify_and ( a, b, [ ] , Adjust :: ReborrowPin ( mut_b) )
833+ self . unify_and ( a, b, [ ] , Adjust :: ReborrowPin ( mut_b) , LeakCheck :: Default )
798834 }
799835
800836 fn coerce_from_safe_fn (
@@ -805,39 +841,26 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
805841 ) -> CoerceResult < ' tcx > {
806842 debug_assert ! ( self . shallow_resolve( b) == b) ;
807843
808- self . commit_if_ok ( |snapshot| {
809- let outer_universe = self . infcx . universe ( ) ;
810-
811- let result = if let ty:: FnPtr ( _, hdr_b) = b. kind ( )
812- && fn_ty_a. safety ( ) . is_safe ( )
813- && hdr_b. safety . is_unsafe ( )
814- {
815- let unsafe_a = self . tcx . safe_to_unsafe_fn_ty ( fn_ty_a) ;
816- self . unify_and (
817- unsafe_a,
818- b,
819- adjustment
820- . map ( |kind| Adjustment { kind, target : Ty :: new_fn_ptr ( self . tcx , fn_ty_a) } ) ,
821- Adjust :: Pointer ( PointerCoercion :: UnsafeFnPointer ) ,
822- )
823- } else {
824- let a = Ty :: new_fn_ptr ( self . tcx , fn_ty_a) ;
825- match adjustment {
826- Some ( adjust) => self . unify_and ( a, b, [ ] , adjust) ,
827- None => self . unify ( a, b) ,
828- }
829- } ;
830-
831- // FIXME(#73154): This is a hack. Currently LUB can generate
832- // unsolvable constraints. Additionally, it returns `a`
833- // unconditionally, even when the "LUB" is `b`. In the future, we
834- // want the coerced type to be the actual supertype of these two,
835- // but for now, we want to just error to ensure we don't lock
836- // ourselves into a specific behavior with NLL.
837- self . leak_check ( outer_universe, Some ( snapshot) ) ?;
838-
839- result
840- } )
844+ if let ty:: FnPtr ( _, hdr_b) = b. kind ( )
845+ && fn_ty_a. safety ( ) . is_safe ( )
846+ && hdr_b. safety . is_unsafe ( )
847+ {
848+ let unsafe_a = self . tcx . safe_to_unsafe_fn_ty ( fn_ty_a) ;
849+ self . unify_and (
850+ unsafe_a,
851+ b,
852+ adjustment
853+ . map ( |kind| Adjustment { kind, target : Ty :: new_fn_ptr ( self . tcx , fn_ty_a) } ) ,
854+ Adjust :: Pointer ( PointerCoercion :: UnsafeFnPointer ) ,
855+ LeakCheck :: Yes ,
856+ )
857+ } else {
858+ let a = Ty :: new_fn_ptr ( self . tcx , fn_ty_a) ;
859+ match adjustment {
860+ Some ( adjust) => self . unify_and ( a, b, [ ] , adjust, LeakCheck :: Yes ) ,
861+ None => self . unify ( a, b, LeakCheck :: Yes ) ,
862+ }
863+ }
841864 }
842865
843866 fn coerce_from_fn_pointer (
@@ -901,7 +924,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
901924 obligations. extend ( o2) ;
902925 Ok ( InferOk { value, obligations } )
903926 }
904- _ => self . unify ( a, b) ,
927+ _ => self . unify ( a, b, LeakCheck :: Default ) ,
905928 }
906929 }
907930
@@ -946,9 +969,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
946969 b,
947970 [ ] ,
948971 Adjust :: Pointer ( PointerCoercion :: ClosureFnPointer ( safety) ) ,
972+ LeakCheck :: Default ,
949973 )
950974 }
951- _ => self . unify ( a, b) ,
975+ _ => self . unify ( a, b, LeakCheck :: Default ) ,
952976 }
953977 }
954978
@@ -965,7 +989,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
965989 let ( is_ref, mt_a) = match * a. kind ( ) {
966990 ty:: Ref ( _, ty, mutbl) => ( true , ty:: TypeAndMut { ty, mutbl } ) ,
967991 ty:: RawPtr ( ty, mutbl) => ( false , ty:: TypeAndMut { ty, mutbl } ) ,
968- _ => return self . unify ( a, b) ,
992+ _ => return self . unify ( a, b, LeakCheck :: Default ) ,
969993 } ;
970994 coerce_mutbls ( mt_a. mutbl , mutbl_b) ?;
971995
@@ -980,11 +1004,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
9801004 b,
9811005 [ Adjustment { kind : Adjust :: Deref ( None ) , target : mt_a. ty } ] ,
9821006 Adjust :: Borrow ( AutoBorrow :: RawPtr ( mutbl_b) ) ,
1007+ LeakCheck :: Default ,
9831008 )
9841009 } else if mt_a. mutbl != mutbl_b {
985- self . unify_and ( a_raw, b, [ ] , Adjust :: Pointer ( PointerCoercion :: MutToConstPointer ) )
1010+ self . unify_and (
1011+ a_raw,
1012+ b,
1013+ [ ] ,
1014+ Adjust :: Pointer ( PointerCoercion :: MutToConstPointer ) ,
1015+ LeakCheck :: Default ,
1016+ )
9861017 } else {
987- self . unify ( a_raw, b)
1018+ self . unify ( a_raw, b, LeakCheck :: Default )
9881019 }
9891020 }
9901021}
@@ -1083,7 +1114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10831114 // We don't ever need two-phase here since we throw out the result of the coercion.
10841115 let coerce = Coerce :: new ( self , cause, AllowTwoPhase :: No , true ) ;
10851116 coerce. autoderef ( DUMMY_SP , expr_ty) . find_map ( |( ty, steps) | {
1086- self . probe ( |_| coerce. unify_raw ( ty, target) ) . ok ( ) . map ( |_| steps)
1117+ self . probe ( |_| coerce. unify_raw ( ty, target, LeakCheck :: Default ) ) . ok ( ) . map ( |_| steps)
10871118 } )
10881119 }
10891120
0 commit comments