@@ -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 ;
@@ -1137,65 +1137,319 @@ fn check_region_bounds_on_impl_item<'tcx>(
11371137 // but found 0" it's confusing, because it looks like there
11381138 // are zero. Since I don't quite know how to phrase things at
11391139 // the moment, give a kind of vague error message.
1140- if trait_params != impl_params {
1141- let span = tcx
1142- . hir_get_generics ( impl_m. def_id . expect_local ( ) )
1143- . expect ( "expected impl item to have generics or else we can't compare them" )
1144- . span ;
1145-
1146- let mut generics_span = None ;
1147- let mut bounds_span = vec ! [ ] ;
1148- let mut where_span = None ;
1149- if let Some ( trait_node) = tcx. hir_get_if_local ( trait_m. def_id )
1150- && let Some ( trait_generics) = trait_node. generics ( )
1151- {
1152- generics_span = Some ( trait_generics. span ) ;
1153- // FIXME: we could potentially look at the impl's bounds to not point at bounds that
1154- // *are* present in the impl.
1155- for p in trait_generics. predicates {
1156- if let hir:: WherePredicateKind :: BoundPredicate ( pred) = p. kind {
1157- for b in pred. bounds {
1140+ if trait_params == impl_params {
1141+ return Ok ( ( ) ) ;
1142+ }
1143+
1144+ if !delay && let Some ( guar) = check_region_late_boundedness ( tcx, impl_m, trait_m) {
1145+ return Err ( guar) ;
1146+ }
1147+
1148+ let span = tcx
1149+ . hir_get_generics ( impl_m. def_id . expect_local ( ) )
1150+ . expect ( "expected impl item to have generics or else we can't compare them" )
1151+ . span ;
1152+
1153+ let mut generics_span = None ;
1154+ let mut bounds_span = vec ! [ ] ;
1155+ let mut where_span = None ;
1156+
1157+ if let Some ( trait_node) = tcx. hir_get_if_local ( trait_m. def_id )
1158+ && let Some ( trait_generics) = trait_node. generics ( )
1159+ {
1160+ generics_span = Some ( trait_generics. span ) ;
1161+ // FIXME: we could potentially look at the impl's bounds to not point at bounds that
1162+ // *are* present in the impl.
1163+ for p in trait_generics. predicates {
1164+ match p. kind {
1165+ hir:: WherePredicateKind :: BoundPredicate ( hir:: WhereBoundPredicate {
1166+ bounds,
1167+ ..
1168+ } )
1169+ | hir:: WherePredicateKind :: RegionPredicate ( hir:: WhereRegionPredicate {
1170+ bounds,
1171+ ..
1172+ } ) => {
1173+ for b in * bounds {
11581174 if let hir:: GenericBound :: Outlives ( lt) = b {
11591175 bounds_span. push ( lt. ident . span ) ;
11601176 }
11611177 }
11621178 }
1179+ _ => { }
11631180 }
1164- if let Some ( impl_node) = tcx. hir_get_if_local ( impl_m. def_id )
1165- && let Some ( impl_generics) = impl_node. generics ( )
1166- {
1167- let mut impl_bounds = 0 ;
1168- for p in impl_generics. predicates {
1169- if let hir:: WherePredicateKind :: BoundPredicate ( pred) = p. kind {
1170- for b in pred. bounds {
1181+ }
1182+ if let Some ( impl_node) = tcx. hir_get_if_local ( impl_m. def_id )
1183+ && let Some ( impl_generics) = impl_node. generics ( )
1184+ {
1185+ let mut impl_bounds = 0 ;
1186+ for p in impl_generics. predicates {
1187+ match p. kind {
1188+ hir:: WherePredicateKind :: BoundPredicate ( hir:: WhereBoundPredicate {
1189+ bounds,
1190+ ..
1191+ } )
1192+ | hir:: WherePredicateKind :: RegionPredicate ( hir:: WhereRegionPredicate {
1193+ bounds,
1194+ ..
1195+ } ) => {
1196+ for b in * bounds {
11711197 if let hir:: GenericBound :: Outlives ( _) = b {
11721198 impl_bounds += 1 ;
11731199 }
11741200 }
11751201 }
1202+ _ => { }
1203+ }
1204+ }
1205+ if impl_bounds == bounds_span. len ( ) {
1206+ bounds_span = vec ! [ ] ;
1207+ } else if impl_generics. has_where_clause_predicates {
1208+ where_span = Some ( impl_generics. where_clause_span ) ;
1209+ }
1210+ }
1211+ }
1212+
1213+ let reported = tcx
1214+ . dcx ( )
1215+ . create_err ( LifetimesOrBoundsMismatchOnTrait {
1216+ span,
1217+ item_kind : impl_m. descr ( ) ,
1218+ ident : impl_m. ident ( tcx) ,
1219+ generics_span,
1220+ bounds_span,
1221+ where_span,
1222+ } )
1223+ . emit_unless ( delay) ;
1224+
1225+ Err ( reported)
1226+ }
1227+
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+ ) ;
11761378 }
1177- if impl_bounds == bounds_span. len ( ) {
1178- bounds_span = vec ! [ ] ;
1179- } else if impl_generics. has_where_clause_predicates {
1180- where_span = Some ( impl_generics. where_clause_span ) ;
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+ ) ;
11811418 }
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+ ) ;
11821426 }
11831427 }
1184- let reported = tcx
1185- . dcx ( )
1186- . create_err ( LifetimesOrBoundsMismatchOnTrait {
1187- span,
1188- item_kind : impl_m. descr ( ) ,
1189- ident : impl_m. ident ( tcx) ,
1190- generics_span,
1191- bounds_span,
1192- where_span,
1193- } )
1194- . emit_unless ( delay) ;
1195- return Err ( reported) ;
11961428 }
11971429
1198- Ok ( ( ) )
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
11991453}
12001454
12011455#[ instrument( level = "debug" , skip( infcx) ) ]
0 commit comments