@@ -1163,8 +1163,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11631163 exprs. len( )
11641164 ) ;
11651165
1166- // The following check fixes #88097, where the compiler erroneously
1167- // attempted to coerce a closure type to itself via a function pointer.
1166+ // Fast Path: don't go through the coercion logic if we're coercing
1167+ // a type to itself. This is unfortunately quite perf relevant so
1168+ // we do it even though it may mask bugs in the coercion logic.
11681169 if prev_ty == new_ty {
11691170 return Ok ( prev_ty) ;
11701171 }
@@ -1193,34 +1194,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11931194 if is_capturing_closure ( prev_ty) || is_capturing_closure ( new_ty) {
11941195 ( None , None )
11951196 } else {
1196- match ( prev_ty. kind ( ) , new_ty. kind ( ) ) {
1197- ( ty:: FnDef ( ..) , ty:: FnDef ( ..) ) => {
1198- // Don't reify if the function types have a LUB, i.e., they
1199- // are the same function and their parameters have a LUB.
1200- match self . commit_if_ok ( |_| {
1201- // We need to eagerly handle nested obligations due to lazy norm.
1202- if self . next_trait_solver ( ) {
1203- let ocx = ObligationCtxt :: new ( self ) ;
1204- let value = ocx. lub ( cause, self . param_env , prev_ty, new_ty) ?;
1205- if ocx. try_evaluate_obligations ( ) . is_empty ( ) {
1206- Ok ( InferOk {
1207- value,
1208- obligations : ocx. into_pending_obligations ( ) ,
1209- } )
1210- } else {
1211- Err ( TypeError :: Mismatch )
1212- }
1197+ let lubbed_tys = || {
1198+ self . commit_if_ok ( |snapshot| {
1199+ let outer_universe = self . infcx . universe ( ) ;
1200+
1201+ // We need to eagerly handle nested obligations due to lazy norm.
1202+ let result = if self . next_trait_solver ( ) {
1203+ let ocx = ObligationCtxt :: new ( self ) ;
1204+ let value = ocx. lub ( cause, self . param_env , prev_ty, new_ty) ?;
1205+ if ocx. try_evaluate_obligations ( ) . is_empty ( ) {
1206+ Ok ( InferOk { value, obligations : ocx. into_pending_obligations ( ) } )
12131207 } else {
1214- self . at ( cause, self . param_env ) . lub ( prev_ty, new_ty)
1215- }
1216- } ) {
1217- // We have a LUB of prev_ty and new_ty, just return it.
1218- Ok ( ok) => return Ok ( self . register_infer_ok_obligations ( ok) ) ,
1219- Err ( _) => {
1220- ( Some ( prev_ty. fn_sig ( self . tcx ) ) , Some ( new_ty. fn_sig ( self . tcx ) ) )
1208+ Err ( TypeError :: Mismatch )
12211209 }
1210+ } else {
1211+ self . at ( cause, self . param_env ) . lub ( prev_ty, new_ty)
1212+ } ;
1213+
1214+ self . leak_check ( outer_universe, Some ( snapshot) ) ?;
1215+ result
1216+ } )
1217+ } ;
1218+
1219+ match ( prev_ty. kind ( ) , new_ty. kind ( ) ) {
1220+ // Don't coerce pairs of fndefs or pairs of closures to fn ptrs
1221+ // if they can just be lubbed.
1222+ //
1223+ // See #88097 or `lub_closures_before_fnptr_coercion.rs` for where
1224+ // we would erroneously coerce closures to fnptrs when attempting to
1225+ // coerce a closure to itself.
1226+ ( ty:: FnDef ( ..) , ty:: FnDef ( ..) ) => match lubbed_tys ( ) {
1227+ Ok ( ok) => return Ok ( self . register_infer_ok_obligations ( ok) ) ,
1228+ Err ( _) => ( Some ( prev_ty. fn_sig ( self . tcx ) ) , Some ( new_ty. fn_sig ( self . tcx ) ) ) ,
1229+ } ,
1230+ ( ty:: Closure ( _, args_a) , ty:: Closure ( _, args_b) ) => match lubbed_tys ( ) {
1231+ Ok ( ok) => return Ok ( self . register_infer_ok_obligations ( ok) ) ,
1232+ Err ( _) => {
1233+ let a_sig = self
1234+ . tcx
1235+ . signature_unclosure ( args_a. as_closure ( ) . sig ( ) , hir:: Safety :: Safe ) ;
1236+ let b_sig = self
1237+ . tcx
1238+ . signature_unclosure ( args_b. as_closure ( ) . sig ( ) , hir:: Safety :: Safe ) ;
1239+ ( Some ( a_sig) , Some ( b_sig) )
12221240 }
1223- }
1241+ } ,
12241242 ( ty:: Closure ( _, args) , ty:: FnDef ( ..) ) => {
12251243 let b_sig = new_ty. fn_sig ( self . tcx ) ;
12261244 let a_sig =
@@ -1233,16 +1251,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12331251 self . tcx . signature_unclosure ( args. as_closure ( ) . sig ( ) , a_sig. safety ( ) ) ;
12341252 ( Some ( a_sig) , Some ( b_sig) )
12351253 }
1236- ( ty:: Closure ( _, args_a) , ty:: Closure ( _, args_b) ) => (
1237- Some (
1238- self . tcx
1239- . signature_unclosure ( args_a. as_closure ( ) . sig ( ) , hir:: Safety :: Safe ) ,
1240- ) ,
1241- Some (
1242- self . tcx
1243- . signature_unclosure ( args_b. as_closure ( ) . sig ( ) , hir:: Safety :: Safe ) ,
1244- ) ,
1245- ) ,
1254+ // ty::FnPtr x ty::FnPtr is fine to just be handled through a normal `unify`
1255+ // call using `lub` which is what will happen on the normal path.
12461256 _ => ( None , None ) ,
12471257 }
12481258 }
0 commit comments