1
1
use std:: iter;
2
2
3
+ use rustc_data_structures:: fx:: FxIndexSet ;
3
4
use rustc_errors:: {
4
5
struct_span_code_err, Applicability , Diag , Subdiagnostic , E0309 , E0310 , E0311 , E0495 ,
5
6
} ;
@@ -12,7 +13,7 @@ use rustc_middle::traits::ObligationCauseCode;
12
13
use rustc_middle:: ty:: error:: TypeError ;
13
14
use rustc_middle:: ty:: { self , IsSuggestable , Region , Ty , TyCtxt , TypeVisitableExt as _} ;
14
15
use rustc_span:: symbol:: kw;
15
- use rustc_span:: { ErrorGuaranteed , Span } ;
16
+ use rustc_span:: { BytePos , ErrorGuaranteed , Span , Symbol } ;
16
17
use rustc_type_ir:: Upcast as _;
17
18
18
19
use super :: nice_region_error:: find_anon_type;
@@ -1201,17 +1202,21 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
1201
1202
"" ,
1202
1203
) ;
1203
1204
if let Some ( reg_info) = tcx. is_suitable_region ( generic_param_scope, hidden_region) {
1204
- let fn_returns = tcx. return_type_impl_or_dyn_traits ( reg_info. def_id ) ;
1205
- nice_region_error:: suggest_new_region_bound (
1206
- tcx,
1207
- & mut err,
1208
- fn_returns,
1209
- hidden_region. to_string ( ) ,
1210
- None ,
1211
- format ! ( "captures `{hidden_region}`" ) ,
1212
- None ,
1213
- Some ( reg_info. def_id ) ,
1214
- )
1205
+ if infcx. tcx . features ( ) . precise_capturing {
1206
+ suggest_precise_capturing ( tcx, opaque_ty_key. def_id , hidden_region, & mut err) ;
1207
+ } else {
1208
+ let fn_returns = tcx. return_type_impl_or_dyn_traits ( reg_info. def_id ) ;
1209
+ nice_region_error:: suggest_new_region_bound (
1210
+ tcx,
1211
+ & mut err,
1212
+ fn_returns,
1213
+ hidden_region. to_string ( ) ,
1214
+ None ,
1215
+ format ! ( "captures `{hidden_region}`" ) ,
1216
+ None ,
1217
+ Some ( reg_info. def_id ) ,
1218
+ )
1219
+ }
1215
1220
}
1216
1221
}
1217
1222
ty:: RePlaceholder ( _) => {
@@ -1257,3 +1262,98 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
1257
1262
1258
1263
err
1259
1264
}
1265
+
1266
+ fn suggest_precise_capturing < ' tcx > (
1267
+ tcx : TyCtxt < ' tcx > ,
1268
+ opaque_def_id : LocalDefId ,
1269
+ captured_lifetime : ty:: Region < ' tcx > ,
1270
+ diag : & mut Diag < ' _ > ,
1271
+ ) {
1272
+ let hir:: OpaqueTy { bounds, .. } =
1273
+ tcx. hir_node_by_def_id ( opaque_def_id) . expect_item ( ) . expect_opaque_ty ( ) ;
1274
+
1275
+ let new_lifetime = Symbol :: intern ( & captured_lifetime. to_string ( ) ) ;
1276
+
1277
+ if let Some ( ( args, span) ) = bounds. iter ( ) . find_map ( |bound| match bound {
1278
+ hir:: GenericBound :: Use ( args, span) => Some ( ( args, span) ) ,
1279
+ _ => None ,
1280
+ } ) {
1281
+ let last_lifetime_span = args. iter ( ) . rev ( ) . find_map ( |arg| match arg {
1282
+ hir:: PreciseCapturingArg :: Lifetime ( lt) => Some ( lt. ident . span ) ,
1283
+ _ => None ,
1284
+ } ) ;
1285
+
1286
+ let first_param_span = args. iter ( ) . find_map ( |arg| match arg {
1287
+ hir:: PreciseCapturingArg :: Param ( p) => Some ( p. ident . span ) ,
1288
+ _ => None ,
1289
+ } ) ;
1290
+
1291
+ let ( insertion_span, pre, post) = if let Some ( last_lifetime_span) = last_lifetime_span {
1292
+ ( last_lifetime_span. shrink_to_hi ( ) , ", " , "" )
1293
+ } else if let Some ( first_param_span) = first_param_span {
1294
+ ( first_param_span. shrink_to_lo ( ) , "" , ", " )
1295
+ } else {
1296
+ ( span. with_hi ( span. hi ( ) - BytePos ( 1 ) ) . shrink_to_hi ( ) , "" , "" )
1297
+ } ;
1298
+
1299
+ diag. span_suggestion_verbose (
1300
+ insertion_span,
1301
+ format ! ( "add `{new_lifetime}` to the `use<...>` bound to explicitly capture it" , ) ,
1302
+ format ! ( "{pre}{new_lifetime}{post}" ) ,
1303
+ Applicability :: MachineApplicable ,
1304
+ ) ;
1305
+ } else {
1306
+ let mut captured_lifetimes = FxIndexSet :: default ( ) ;
1307
+ let mut captured_non_lifetimes = FxIndexSet :: default ( ) ;
1308
+
1309
+ let variances = tcx. variances_of ( opaque_def_id) ;
1310
+ let mut generics = tcx. generics_of ( opaque_def_id) ;
1311
+ loop {
1312
+ for param in & generics. own_params {
1313
+ if variances[ param. index as usize ] == ty:: Bivariant {
1314
+ continue ;
1315
+ }
1316
+
1317
+ match param. kind {
1318
+ ty:: GenericParamDefKind :: Lifetime => {
1319
+ captured_lifetimes. insert ( param. name ) ;
1320
+ }
1321
+ ty:: GenericParamDefKind :: Type { synthetic : true , .. } => {
1322
+ // FIXME: We can't provide a good suggestion for
1323
+ // `use<...>` if we have an APIT. Bail for now.
1324
+ return ;
1325
+ }
1326
+ ty:: GenericParamDefKind :: Type { .. }
1327
+ | ty:: GenericParamDefKind :: Const { .. } => {
1328
+ captured_non_lifetimes. insert ( param. name ) ;
1329
+ }
1330
+ }
1331
+ }
1332
+
1333
+ if let Some ( parent) = generics. parent {
1334
+ generics = tcx. generics_of ( parent) ;
1335
+ } else {
1336
+ break ;
1337
+ }
1338
+ }
1339
+
1340
+ if !captured_lifetimes. insert ( new_lifetime) {
1341
+ // Uh, strange. This lifetime appears to already be captured...
1342
+ return ;
1343
+ }
1344
+
1345
+ let concatenated_bounds = captured_lifetimes
1346
+ . into_iter ( )
1347
+ . chain ( captured_non_lifetimes)
1348
+ . map ( |sym| sym. to_string ( ) )
1349
+ . collect :: < Vec < _ > > ( )
1350
+ . join ( ", " ) ;
1351
+
1352
+ diag. span_suggestion_verbose (
1353
+ tcx. def_span ( opaque_def_id) . shrink_to_hi ( ) ,
1354
+ format ! ( "add a `use<...>` bound to explicitly capture `{new_lifetime}`" , ) ,
1355
+ format ! ( " + use<{concatenated_bounds}>" ) ,
1356
+ Applicability :: MachineApplicable ,
1357
+ ) ;
1358
+ }
1359
+ }
0 commit comments