17
17
use rustc_ast:: Recovered ;
18
18
use rustc_data_structures:: captures:: Captures ;
19
19
use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
20
- use rustc_data_structures:: unord:: UnordMap ;
20
+ use rustc_data_structures:: unord:: { UnordMap , UnordSet } ;
21
21
use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , StashKey } ;
22
22
use rustc_hir as hir;
23
23
use rustc_hir:: def:: DefKind ;
@@ -41,6 +41,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
41
41
use std:: cell:: Cell ;
42
42
use std:: iter;
43
43
use std:: ops:: Bound ;
44
+ use std:: ops:: ControlFlow ;
44
45
45
46
use crate :: check:: intrinsic:: intrinsic_operation_unsafety;
46
47
use crate :: errors;
@@ -1290,12 +1291,12 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
1290
1291
kind : TraitItemKind :: Fn ( sig, TraitFn :: Provided ( _) ) ,
1291
1292
generics,
1292
1293
..
1293
- } )
1294
- | Item ( hir:: Item { kind : ItemKind :: Fn ( sig, generics, _ ) , .. } ) => {
1295
- infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, & icx)
1294
+ } ) => infer_return_ty_for_fn_sig ( tcx , sig , generics , def_id , None , & icx ) ,
1295
+ Item ( hir:: Item { kind : ItemKind :: Fn ( sig, generics, body_id ) , .. } ) => {
1296
+ infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, Some ( * body_id ) , & icx)
1296
1297
}
1297
1298
1298
- ImplItem ( hir:: ImplItem { kind : ImplItemKind :: Fn ( sig, _ ) , generics, .. } ) => {
1299
+ ImplItem ( hir:: ImplItem { kind : ImplItemKind :: Fn ( sig, body_id ) , generics, .. } ) => {
1299
1300
// Do not try to infer the return type for a impl method coming from a trait
1300
1301
if let Item ( hir:: Item { kind : ItemKind :: Impl ( i) , .. } ) = tcx. parent_hir_node ( hir_id)
1301
1302
&& i. of_trait . is_some ( )
@@ -1309,7 +1310,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
1309
1310
None ,
1310
1311
)
1311
1312
} else {
1312
- infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, & icx)
1313
+ infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, Some ( * body_id ) , & icx)
1313
1314
}
1314
1315
}
1315
1316
@@ -1364,13 +1365,15 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1364
1365
sig : & hir:: FnSig < ' tcx > ,
1365
1366
generics : & hir:: Generics < ' _ > ,
1366
1367
def_id : LocalDefId ,
1368
+ body_id : Option < hir:: BodyId > ,
1367
1369
icx : & ItemCtxt < ' tcx > ,
1368
1370
) -> ty:: PolyFnSig < ' tcx > {
1369
1371
let hir_id = tcx. local_def_id_to_hir_id ( def_id) ;
1370
1372
1371
1373
match sig. decl . output . get_infer_ret_ty ( ) {
1372
1374
Some ( ty) => {
1373
1375
let fn_sig = tcx. typeck ( def_id) . liberated_fn_sigs ( ) [ hir_id] ;
1376
+ let keep_erased_ret_ty = fn_sig. output ( ) ;
1374
1377
// Typeck doesn't expect erased regions to be returned from `type_of`.
1375
1378
let fn_sig = tcx. fold_regions ( fn_sig, |r, _| match * r {
1376
1379
ty:: ReErased => tcx. lifetimes . re_static ,
@@ -1380,6 +1383,78 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1380
1383
let mut visitor = HirPlaceholderCollector :: default ( ) ;
1381
1384
visitor. visit_ty ( ty) ;
1382
1385
1386
+ // When the return value of a Function is one of its params,
1387
+ // we shouldn't change the `Erased` lifetime to `Static` lifetime.
1388
+ // For example:
1389
+ // fn main() {
1390
+ // fn f1(s: S<'_>) -> _ {
1391
+ // s
1392
+ // }
1393
+ // }
1394
+ // -----------------------^--
1395
+ // We should suggest replace `_` with `S<'_>`.
1396
+ let mut keep_erased_lifetime = false ;
1397
+ if let Some ( body_id) = body_id {
1398
+ struct RetVisitor {
1399
+ res_hir_ids : UnordSet < hir:: HirId > ,
1400
+ }
1401
+
1402
+ impl < ' v > Visitor < ' v > for RetVisitor {
1403
+ type Result = ControlFlow < ( ) > ;
1404
+
1405
+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) -> Self :: Result {
1406
+ if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ex. kind
1407
+ && let hir:: def:: Res :: Local ( hir_id) = path. res
1408
+ && self . res_hir_ids . contains ( & hir_id)
1409
+ {
1410
+ ControlFlow :: Break ( ( ) )
1411
+ } else if let hir:: ExprKind :: If ( _, expr, _) = ex. kind
1412
+ && let hir:: ExprKind :: Block ( block, _) = expr. kind
1413
+ {
1414
+ self . visit_block ( block)
1415
+ } else {
1416
+ ControlFlow :: Continue ( ( ) )
1417
+ }
1418
+ }
1419
+
1420
+ fn visit_block ( & mut self , b : & ' v hir:: Block < ' v > ) -> Self :: Result {
1421
+ if let Some ( ret) = b. expr {
1422
+ self . visit_expr ( ret)
1423
+ } else if let Some ( ret) = b. stmts . last ( ) {
1424
+ self . visit_stmt ( ret)
1425
+ } else {
1426
+ ControlFlow :: Continue ( ( ) )
1427
+ }
1428
+ }
1429
+
1430
+ fn visit_stmt ( & mut self , s : & ' v hir:: Stmt < ' v > ) -> Self :: Result {
1431
+ if let hir:: StmtKind :: Semi ( expr) = s. kind
1432
+ && let hir:: ExprKind :: Ret ( Some ( ret) ) = expr. kind
1433
+ {
1434
+ self . visit_expr ( ret)
1435
+ } else {
1436
+ ControlFlow :: Continue ( ( ) )
1437
+ }
1438
+ }
1439
+
1440
+ fn visit_item ( & mut self , _i : & ' v hir:: Item < ' v > ) -> Self :: Result {
1441
+ ControlFlow :: Continue ( ( ) )
1442
+ }
1443
+ }
1444
+
1445
+ let body = tcx. hir ( ) . body ( body_id) ;
1446
+ if let hir:: ExprKind :: Block ( b, _) = body. value . kind {
1447
+ let mut res_hir_ids = UnordSet :: new ( ) ;
1448
+ for param in body. params {
1449
+ res_hir_ids. insert ( param. pat . hir_id ) ;
1450
+ }
1451
+ let mut ret_visitor = RetVisitor { res_hir_ids } ;
1452
+ if let ControlFlow :: Break ( ( ) ) = ret_visitor. visit_block ( b) {
1453
+ keep_erased_lifetime = true ;
1454
+ }
1455
+ }
1456
+ }
1457
+
1383
1458
let mut diag = bad_placeholder ( tcx, visitor. 0 , "return type" ) ;
1384
1459
let ret_ty = fn_sig. output ( ) ;
1385
1460
// Don't leak types into signatures unless they're nameable!
@@ -1388,13 +1463,20 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1388
1463
let mut recovered_ret_ty = None ;
1389
1464
1390
1465
if let Some ( suggestable_ret_ty) = ret_ty. make_suggestable ( tcx, false , None ) {
1466
+ recovered_ret_ty = Some ( suggestable_ret_ty) ;
1467
+
1391
1468
diag. span_suggestion (
1392
1469
ty. span ,
1393
1470
"replace with the correct return type" ,
1394
- suggestable_ret_ty,
1471
+ if keep_erased_lifetime
1472
+ && let Some ( ty) = keep_erased_ret_ty. make_suggestable ( tcx, false , None )
1473
+ {
1474
+ ty
1475
+ } else {
1476
+ suggestable_ret_ty
1477
+ } ,
1395
1478
Applicability :: MachineApplicable ,
1396
1479
) ;
1397
- recovered_ret_ty = Some ( suggestable_ret_ty) ;
1398
1480
} else if let Some ( sugg) =
1399
1481
suggest_impl_trait ( & tcx. infer_ctxt ( ) . build ( ) , tcx. param_env ( def_id) , ret_ty)
1400
1482
{
0 commit comments