@@ -5,7 +5,7 @@ use std::iter;
55use hir:: def_id:: { DefId , DefIdMap , LocalDefId } ;
66use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
77use rustc_errors:: codes:: * ;
8- use rustc_errors:: { Applicability , ErrorGuaranteed , pluralize, struct_span_code_err} ;
8+ use rustc_errors:: { Applicability , ErrorGuaranteed , MultiSpan , pluralize, struct_span_code_err} ;
99use rustc_hir:: def:: { DefKind , Res } ;
1010use rustc_hir:: intravisit:: VisitorExt ;
1111use rustc_hir:: { self as hir, AmbigArg , GenericParamKind , ImplItemKind , intravisit} ;
@@ -14,10 +14,10 @@ use rustc_infer::traits::util;
1414use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
1515use rustc_middle:: ty:: {
1616 self , BottomUpFolder , GenericArgs , GenericParamDefKind , Ty , TyCtxt , TypeFoldable , TypeFolder ,
17- TypeSuperFoldable , TypeVisitableExt , TypingMode , Upcast ,
17+ TypeSuperFoldable , TypeVisitable , TypeVisitableExt , TypeVisitor , TypingMode , Upcast ,
1818} ;
1919use rustc_middle:: { bug, span_bug} ;
20- use rustc_span:: Span ;
20+ use rustc_span:: { DUMMY_SP , Span } ;
2121use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
2222use rustc_trait_selection:: infer:: InferCtxtExt ;
2323use rustc_trait_selection:: regions:: InferCtxtRegionExt ;
@@ -1141,6 +1141,10 @@ fn check_region_bounds_on_impl_item<'tcx>(
11411141 return Ok ( ( ) ) ;
11421142 }
11431143
1144+ if !delay && let Some ( guar) = check_region_late_boundedness ( tcx, impl_m, trait_m) {
1145+ return Err ( guar) ;
1146+ }
1147+
11441148 let span = tcx
11451149 . hir_get_generics ( impl_m. def_id . expect_local ( ) )
11461150 . expect ( "expected impl item to have generics or else we can't compare them" )
@@ -1221,6 +1225,233 @@ fn check_region_bounds_on_impl_item<'tcx>(
12211225 Err ( reported)
12221226}
12231227
1228+ #[ allow( unused) ]
1229+ enum LateEarlyMismatch < ' tcx > {
1230+ EarlyInImpl ( DefId , DefId , ty:: Region < ' tcx > ) ,
1231+ LateInImpl ( DefId , DefId , ty:: Region < ' tcx > ) ,
1232+ }
1233+
1234+ fn check_region_late_boundedness < ' tcx > (
1235+ tcx : TyCtxt < ' tcx > ,
1236+ impl_m : ty:: AssocItem ,
1237+ trait_m : ty:: AssocItem ,
1238+ ) -> Option < ErrorGuaranteed > {
1239+ if !impl_m. is_fn ( ) {
1240+ return None ;
1241+ }
1242+
1243+ let ( infcx, param_env) = tcx
1244+ . infer_ctxt ( )
1245+ . build_with_typing_env ( ty:: TypingEnv :: non_body_analysis ( tcx, impl_m. def_id ) ) ;
1246+
1247+ let impl_m_args = infcx. fresh_args_for_item ( DUMMY_SP , impl_m. def_id ) ;
1248+ let impl_m_sig = tcx. fn_sig ( impl_m. def_id ) . instantiate ( tcx, impl_m_args) ;
1249+ let impl_m_sig = tcx. liberate_late_bound_regions ( impl_m. def_id , impl_m_sig) ;
1250+
1251+ let trait_m_args = infcx. fresh_args_for_item ( DUMMY_SP , trait_m. def_id ) ;
1252+ let trait_m_sig = tcx. fn_sig ( trait_m. def_id ) . instantiate ( tcx, trait_m_args) ;
1253+ let trait_m_sig = tcx. liberate_late_bound_regions ( impl_m. def_id , trait_m_sig) ;
1254+
1255+ let ocx = ObligationCtxt :: new ( & infcx) ;
1256+
1257+ // Equate the signatures so that we can infer whether a late-bound param was present where
1258+ // an early-bound param was expected, since we replace the late-bound lifetimes with
1259+ // `ReLateParam`, and early-bound lifetimes with infer vars, so the early-bound args will
1260+ // resolve to `ReLateParam` if there is a mismatch.
1261+ let Ok ( ( ) ) = ocx. eq (
1262+ & ObligationCause :: dummy ( ) ,
1263+ param_env,
1264+ ty:: Binder :: dummy ( trait_m_sig) ,
1265+ ty:: Binder :: dummy ( impl_m_sig) ,
1266+ ) else {
1267+ return None ;
1268+ } ;
1269+
1270+ let errors = ocx. select_where_possible ( ) ;
1271+ if !errors. is_empty ( ) {
1272+ return None ;
1273+ }
1274+
1275+ let mut mismatched = vec ! [ ] ;
1276+
1277+ let impl_generics = tcx. generics_of ( impl_m. def_id ) ;
1278+ for ( id_arg, arg) in
1279+ std:: iter:: zip ( ty:: GenericArgs :: identity_for_item ( tcx, impl_m. def_id ) , impl_m_args)
1280+ {
1281+ if let ty:: GenericArgKind :: Lifetime ( r) = arg. unpack ( )
1282+ && let ty:: ReVar ( vid) = r. kind ( )
1283+ && let r = infcx
1284+ . inner
1285+ . borrow_mut ( )
1286+ . unwrap_region_constraints ( )
1287+ . opportunistic_resolve_var ( tcx, vid)
1288+ && let ty:: ReLateParam ( ty:: LateParamRegion {
1289+ kind : ty:: LateParamRegionKind :: Named ( trait_param_def_id, _) ,
1290+ ..
1291+ } ) = r. kind ( )
1292+ && let ty:: ReEarlyParam ( ebr) = id_arg. expect_region ( ) . kind ( )
1293+ {
1294+ mismatched. push ( LateEarlyMismatch :: EarlyInImpl (
1295+ impl_generics. region_param ( ebr, tcx) . def_id ,
1296+ trait_param_def_id,
1297+ id_arg. expect_region ( ) ,
1298+ ) ) ;
1299+ }
1300+ }
1301+
1302+ let trait_generics = tcx. generics_of ( trait_m. def_id ) ;
1303+ for ( id_arg, arg) in
1304+ std:: iter:: zip ( ty:: GenericArgs :: identity_for_item ( tcx, trait_m. def_id ) , trait_m_args)
1305+ {
1306+ if let ty:: GenericArgKind :: Lifetime ( r) = arg. unpack ( )
1307+ && let ty:: ReVar ( vid) = r. kind ( )
1308+ && let r = infcx
1309+ . inner
1310+ . borrow_mut ( )
1311+ . unwrap_region_constraints ( )
1312+ . opportunistic_resolve_var ( tcx, vid)
1313+ && let ty:: ReLateParam ( ty:: LateParamRegion {
1314+ kind : ty:: LateParamRegionKind :: Named ( impl_param_def_id, _) ,
1315+ ..
1316+ } ) = r. kind ( )
1317+ && let ty:: ReEarlyParam ( ebr) = id_arg. expect_region ( ) . kind ( )
1318+ {
1319+ mismatched. push ( LateEarlyMismatch :: LateInImpl (
1320+ impl_param_def_id,
1321+ trait_generics. region_param ( ebr, tcx) . def_id ,
1322+ id_arg. expect_region ( ) ,
1323+ ) ) ;
1324+ }
1325+ }
1326+
1327+ if mismatched. is_empty ( ) {
1328+ return None ;
1329+ }
1330+
1331+ let spans: Vec < _ > = mismatched
1332+ . iter ( )
1333+ . map ( |param| {
1334+ let ( LateEarlyMismatch :: EarlyInImpl ( impl_param_def_id, ..)
1335+ | LateEarlyMismatch :: LateInImpl ( impl_param_def_id, ..) ) = param;
1336+ tcx. def_span ( impl_param_def_id)
1337+ } )
1338+ . collect ( ) ;
1339+
1340+ let mut diag = tcx
1341+ . dcx ( )
1342+ . struct_span_err ( spans, "lifetime parameters do not match the trait definition" )
1343+ . with_note ( "lifetime parameters differ in whether they are early- or late-bound" )
1344+ . with_code ( E0195 ) ;
1345+ for mismatch in mismatched {
1346+ match mismatch {
1347+ LateEarlyMismatch :: EarlyInImpl (
1348+ impl_param_def_id,
1349+ trait_param_def_id,
1350+ early_bound_region,
1351+ ) => {
1352+ let mut multispan = MultiSpan :: from_spans ( vec ! [
1353+ tcx. def_span( impl_param_def_id) ,
1354+ tcx. def_span( trait_param_def_id) ,
1355+ ] ) ;
1356+ multispan
1357+ . push_span_label ( tcx. def_span ( tcx. parent ( impl_m. def_id ) ) , "in this impl..." ) ;
1358+ multispan
1359+ . push_span_label ( tcx. def_span ( tcx. parent ( trait_m. def_id ) ) , "in this trait..." ) ;
1360+ multispan. push_span_label (
1361+ tcx. def_span ( impl_param_def_id) ,
1362+ format ! ( "`{}` is early-bound" , tcx. item_name( impl_param_def_id) ) ,
1363+ ) ;
1364+ multispan. push_span_label (
1365+ tcx. def_span ( trait_param_def_id) ,
1366+ format ! ( "`{}` is late-bound" , tcx. item_name( trait_param_def_id) ) ,
1367+ ) ;
1368+ if let Some ( span) =
1369+ find_region_in_predicates ( tcx, impl_m. def_id , early_bound_region)
1370+ {
1371+ multispan. push_span_label (
1372+ span,
1373+ format ! (
1374+ "this lifetime bound makes `{}` early-bound" ,
1375+ tcx. item_name( impl_param_def_id)
1376+ ) ,
1377+ ) ;
1378+ }
1379+ diag. span_note (
1380+ multispan,
1381+ format ! (
1382+ "`{}` differs between the trait and impl" ,
1383+ tcx. item_name( impl_param_def_id)
1384+ ) ,
1385+ ) ;
1386+ }
1387+ LateEarlyMismatch :: LateInImpl (
1388+ impl_param_def_id,
1389+ trait_param_def_id,
1390+ early_bound_region,
1391+ ) => {
1392+ let mut multispan = MultiSpan :: from_spans ( vec ! [
1393+ tcx. def_span( impl_param_def_id) ,
1394+ tcx. def_span( trait_param_def_id) ,
1395+ ] ) ;
1396+ multispan
1397+ . push_span_label ( tcx. def_span ( tcx. parent ( impl_m. def_id ) ) , "in this impl..." ) ;
1398+ multispan
1399+ . push_span_label ( tcx. def_span ( tcx. parent ( trait_m. def_id ) ) , "in this trait..." ) ;
1400+ multispan. push_span_label (
1401+ tcx. def_span ( impl_param_def_id) ,
1402+ format ! ( "`{}` is late-bound" , tcx. item_name( impl_param_def_id) ) ,
1403+ ) ;
1404+ multispan. push_span_label (
1405+ tcx. def_span ( trait_param_def_id) ,
1406+ format ! ( "`{}` is early-bound" , tcx. item_name( trait_param_def_id) ) ,
1407+ ) ;
1408+ if let Some ( span) =
1409+ find_region_in_predicates ( tcx, trait_m. def_id , early_bound_region)
1410+ {
1411+ multispan. push_span_label (
1412+ span,
1413+ format ! (
1414+ "this lifetime bound makes `{}` early-bound" ,
1415+ tcx. item_name( trait_param_def_id)
1416+ ) ,
1417+ ) ;
1418+ }
1419+ diag. span_note (
1420+ multispan,
1421+ format ! (
1422+ "`{}` differs between the trait and impl" ,
1423+ tcx. item_name( impl_param_def_id)
1424+ ) ,
1425+ ) ;
1426+ }
1427+ }
1428+ }
1429+
1430+ Some ( diag. emit ( ) )
1431+ }
1432+
1433+ fn find_region_in_predicates < ' tcx > (
1434+ tcx : TyCtxt < ' tcx > ,
1435+ def_id : DefId ,
1436+ early_bound_region : ty:: Region < ' tcx > ,
1437+ ) -> Option < Span > {
1438+ for ( pred, span) in tcx. explicit_predicates_of ( def_id) . instantiate_identity ( tcx) {
1439+ if pred. visit_with ( & mut FindRegion ( early_bound_region) ) . is_break ( ) {
1440+ return Some ( span) ;
1441+ }
1442+ }
1443+
1444+ struct FindRegion < ' tcx > ( ty:: Region < ' tcx > ) ;
1445+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for FindRegion < ' tcx > {
1446+ type Result = ControlFlow < ( ) > ;
1447+ fn visit_region ( & mut self , r : ty:: Region < ' tcx > ) -> Self :: Result {
1448+ if r == self . 0 { ControlFlow :: Break ( ( ) ) } else { ControlFlow :: Continue ( ( ) ) }
1449+ }
1450+ }
1451+
1452+ None
1453+ }
1454+
12241455#[ instrument( level = "debug" , skip( infcx) ) ]
12251456fn extract_spans_for_error_reporting < ' tcx > (
12261457 infcx : & infer:: InferCtxt < ' tcx > ,
0 commit comments