@@ -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 ;
@@ -1137,65 +1137,319 @@ fn check_region_bounds_on_impl_item<'tcx>(
1137
1137
// but found 0" it's confusing, because it looks like there
1138
1138
// are zero. Since I don't quite know how to phrase things at
1139
1139
// 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 {
1158
1174
if let hir:: GenericBound :: Outlives ( lt) = b {
1159
1175
bounds_span. push ( lt. ident . span ) ;
1160
1176
}
1161
1177
}
1162
1178
}
1179
+ _ => { }
1163
1180
}
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 {
1171
1197
if let hir:: GenericBound :: Outlives ( _) = b {
1172
1198
impl_bounds += 1 ;
1173
1199
}
1174
1200
}
1175
1201
}
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
+ ) ;
1176
1378
}
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
+ ) ;
1181
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
+ ) ;
1182
1426
}
1183
1427
}
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) ;
1196
1428
}
1197
1429
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
1199
1453
}
1200
1454
1201
1455
#[ instrument( level = "debug" , skip( infcx) ) ]
0 commit comments