11use std:: iter;
22
3+ use rustc_data_structures:: fx:: FxIndexSet ;
34use rustc_errors:: {
45 struct_span_code_err, Applicability , Diag , Subdiagnostic , E0309 , E0310 , E0311 , E0495 ,
56} ;
@@ -12,7 +13,7 @@ use rustc_middle::traits::ObligationCauseCode;
1213use rustc_middle:: ty:: error:: TypeError ;
1314use rustc_middle:: ty:: { self , IsSuggestable , Region , Ty , TyCtxt , TypeVisitableExt as _} ;
1415use rustc_span:: symbol:: kw;
15- use rustc_span:: { ErrorGuaranteed , Span } ;
16+ use rustc_span:: { BytePos , ErrorGuaranteed , Span , Symbol } ;
1617use rustc_type_ir:: Upcast as _;
1718
1819use super :: nice_region_error:: find_anon_type;
@@ -1201,17 +1202,21 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
12011202 "" ,
12021203 ) ;
12031204 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+ }
12151220 }
12161221 }
12171222 ty:: RePlaceholder ( _) => {
@@ -1257,3 +1262,98 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
12571262
12581263 err
12591264}
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