@@ -5,7 +5,7 @@ use std::iter;
5
5
use hir:: def_id:: { DefId , DefIdMap , LocalDefId } ;
6
6
use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
7
7
use 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} ;
9
9
use rustc_hir:: def:: { DefKind , Res } ;
10
10
use rustc_hir:: intravisit:: VisitorExt ;
11
11
use rustc_hir:: { self as hir, AmbigArg , GenericParamKind , ImplItemKind , intravisit} ;
@@ -14,10 +14,10 @@ use rustc_infer::traits::util;
14
14
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
15
15
use rustc_middle:: ty:: {
16
16
self , BottomUpFolder , GenericArgs , GenericParamDefKind , Ty , TyCtxt , TypeFoldable , TypeFolder ,
17
- TypeSuperFoldable , TypeVisitableExt , TypingMode , Upcast ,
17
+ TypeSuperFoldable , TypeVisitable , TypeVisitableExt , TypeVisitor , TypingMode , Upcast ,
18
18
} ;
19
19
use rustc_middle:: { bug, span_bug} ;
20
- use rustc_span:: Span ;
20
+ use rustc_span:: { DUMMY_SP , Span } ;
21
21
use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
22
22
use rustc_trait_selection:: infer:: InferCtxtExt ;
23
23
use rustc_trait_selection:: regions:: InferCtxtRegionExt ;
@@ -1141,6 +1141,10 @@ fn check_region_bounds_on_impl_item<'tcx>(
1141
1141
return Ok ( ( ) ) ;
1142
1142
}
1143
1143
1144
+ if !delay && let Some ( guar) = check_region_late_boundedness ( tcx, impl_m, trait_m) {
1145
+ return Err ( guar) ;
1146
+ }
1147
+
1144
1148
let span = tcx
1145
1149
. hir_get_generics ( impl_m. def_id . expect_local ( ) )
1146
1150
. 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>(
1221
1225
Err ( reported)
1222
1226
}
1223
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
+ ) ;
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
+
1224
1455
#[ instrument( level = "debug" , skip( infcx) ) ]
1225
1456
fn extract_spans_for_error_reporting < ' tcx > (
1226
1457
infcx : & infer:: InferCtxt < ' tcx > ,
0 commit comments