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:: { struct_span_code_err, Applicability , Diag , ErrorGuaranteed , StashKey , E0228 } ;
22
22
use rustc_hir:: def:: DefKind ;
23
23
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
@@ -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;
@@ -1375,12 +1376,12 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
1375
1376
kind : TraitItemKind :: Fn ( sig, TraitFn :: Provided ( _) ) ,
1376
1377
generics,
1377
1378
..
1378
- } )
1379
- | Item ( hir:: Item { kind : ItemKind :: Fn ( sig, generics, _ ) , .. } ) => {
1380
- infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, & icx)
1379
+ } ) => infer_return_ty_for_fn_sig ( tcx , sig , generics , def_id , None , & icx ) ,
1380
+ Item ( hir:: Item { kind : ItemKind :: Fn ( sig, generics, body_id ) , .. } ) => {
1381
+ infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, Some ( * body_id ) , & icx)
1381
1382
}
1382
1383
1383
- ImplItem ( hir:: ImplItem { kind : ImplItemKind :: Fn ( sig, _ ) , generics, .. } ) => {
1384
+ ImplItem ( hir:: ImplItem { kind : ImplItemKind :: Fn ( sig, body_id ) , generics, .. } ) => {
1384
1385
// Do not try to infer the return type for a impl method coming from a trait
1385
1386
if let Item ( hir:: Item { kind : ItemKind :: Impl ( i) , .. } ) = tcx. parent_hir_node ( hir_id)
1386
1387
&& i. of_trait . is_some ( )
@@ -1394,7 +1395,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
1394
1395
None ,
1395
1396
)
1396
1397
} else {
1397
- infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, & icx)
1398
+ infer_return_ty_for_fn_sig ( tcx, sig, generics, def_id, Some ( * body_id ) , & icx)
1398
1399
}
1399
1400
}
1400
1401
@@ -1451,13 +1452,15 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1451
1452
sig : & hir:: FnSig < ' tcx > ,
1452
1453
generics : & hir:: Generics < ' _ > ,
1453
1454
def_id : LocalDefId ,
1455
+ body_id : Option < hir:: BodyId > ,
1454
1456
icx : & ItemCtxt < ' tcx > ,
1455
1457
) -> ty:: PolyFnSig < ' tcx > {
1456
1458
let hir_id = tcx. local_def_id_to_hir_id ( def_id) ;
1457
1459
1458
1460
match sig. decl . output . get_infer_ret_ty ( ) {
1459
1461
Some ( ty) => {
1460
1462
let fn_sig = tcx. typeck ( def_id) . liberated_fn_sigs ( ) [ hir_id] ;
1463
+ let keep_erased_ret_ty = fn_sig. output ( ) ;
1461
1464
// Typeck doesn't expect erased regions to be returned from `type_of`.
1462
1465
let fn_sig = tcx. fold_regions ( fn_sig, |r, _| match * r {
1463
1466
ty:: ReErased => tcx. lifetimes . re_static ,
@@ -1475,13 +1478,20 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1475
1478
let mut recovered_ret_ty = None ;
1476
1479
1477
1480
if let Some ( suggestable_ret_ty) = ret_ty. make_suggestable ( tcx, false , None ) {
1481
+ recovered_ret_ty = Some ( suggestable_ret_ty) ;
1482
+
1478
1483
diag. span_suggestion (
1479
1484
ty. span ,
1480
1485
"replace with the correct return type" ,
1481
- suggestable_ret_ty,
1486
+ if return_value_from_fn_param ( tcx, body_id)
1487
+ && let Some ( ty) = keep_erased_ret_ty. make_suggestable ( tcx, false , None )
1488
+ {
1489
+ ty
1490
+ } else {
1491
+ suggestable_ret_ty
1492
+ } ,
1482
1493
Applicability :: MachineApplicable ,
1483
1494
) ;
1484
- recovered_ret_ty = Some ( suggestable_ret_ty) ;
1485
1495
} else if let Some ( sugg) =
1486
1496
suggest_impl_trait ( & tcx. infer_ctxt ( ) . build ( ) , tcx. param_env ( def_id) , ret_ty)
1487
1497
{
@@ -1522,6 +1532,85 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1522
1532
}
1523
1533
}
1524
1534
1535
+ // When the return value of a Function is one of its params,
1536
+ // we shouldn't change the `Erased` lifetime to `Static` lifetime.
1537
+ // For example:
1538
+ // fn main() {
1539
+ // fn f1(s: S<'_>) -> _ {
1540
+ // s
1541
+ // }
1542
+ // }
1543
+ // -----------------------^--
1544
+ // We should suggest replace `_` with `S<'_>`.
1545
+ fn return_value_from_fn_param < ' tcx > ( tcx : TyCtxt < ' tcx > , body_id_opt : Option < hir:: BodyId > ) -> bool {
1546
+ let body_id = if let Some ( id) = body_id_opt {
1547
+ id
1548
+ } else {
1549
+ return false ;
1550
+ } ;
1551
+
1552
+ struct RetVisitor {
1553
+ res_hir_ids : UnordSet < hir:: HirId > ,
1554
+ }
1555
+
1556
+ impl < ' v > Visitor < ' v > for RetVisitor {
1557
+ type Result = ControlFlow < ( ) > ;
1558
+
1559
+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) -> Self :: Result {
1560
+ match ex. kind {
1561
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) )
1562
+ if let hir:: def:: Res :: Local ( hir_id) = path. res
1563
+ && self . res_hir_ids . contains ( & hir_id) =>
1564
+ {
1565
+ ControlFlow :: Break ( ( ) )
1566
+ }
1567
+ hir:: ExprKind :: If ( _, expr, _) if let hir:: ExprKind :: Block ( block, _) = expr. kind => {
1568
+ self . visit_block ( block)
1569
+ }
1570
+ hir:: ExprKind :: AddrOf ( hir:: BorrowKind :: Ref , _, expr) => self . visit_expr ( expr) ,
1571
+ _ => ControlFlow :: Continue ( ( ) ) ,
1572
+ }
1573
+ }
1574
+
1575
+ fn visit_block ( & mut self , b : & ' v hir:: Block < ' v > ) -> Self :: Result {
1576
+ if let Some ( ret) = b. expr {
1577
+ self . visit_expr ( ret)
1578
+ } else if let Some ( ret) = b. stmts . last ( ) {
1579
+ self . visit_stmt ( ret)
1580
+ } else {
1581
+ ControlFlow :: Continue ( ( ) )
1582
+ }
1583
+ }
1584
+
1585
+ fn visit_stmt ( & mut self , s : & ' v hir:: Stmt < ' v > ) -> Self :: Result {
1586
+ if let hir:: StmtKind :: Semi ( expr) = s. kind
1587
+ && let hir:: ExprKind :: Ret ( Some ( ret) ) = expr. kind
1588
+ {
1589
+ self . visit_expr ( ret)
1590
+ } else {
1591
+ ControlFlow :: Continue ( ( ) )
1592
+ }
1593
+ }
1594
+
1595
+ fn visit_item ( & mut self , _i : & ' v hir:: Item < ' v > ) -> Self :: Result {
1596
+ ControlFlow :: Continue ( ( ) )
1597
+ }
1598
+ }
1599
+
1600
+ let body = tcx. hir ( ) . body ( body_id) ;
1601
+ if let hir:: ExprKind :: Block ( b, _) = body. value . kind {
1602
+ let mut res_hir_ids = UnordSet :: new ( ) ;
1603
+ for param in body. params {
1604
+ res_hir_ids. insert ( param. pat . hir_id ) ;
1605
+ }
1606
+ let mut ret_visitor = RetVisitor { res_hir_ids } ;
1607
+ if let ControlFlow :: Break ( ( ) ) = ret_visitor. visit_block ( b) {
1608
+ return true ;
1609
+ }
1610
+ }
1611
+ false
1612
+ }
1613
+
1525
1614
pub fn suggest_impl_trait < ' tcx > (
1526
1615
infcx : & InferCtxt < ' tcx > ,
1527
1616
param_env : ty:: ParamEnv < ' tcx > ,
0 commit comments