36
36
//! ```
37
37
38
38
use crate :: FnCtxt ;
39
- use rustc_errors:: { codes:: * , struct_span_code_err, Applicability , Diag , MultiSpan } ;
39
+ use rustc_errors:: { codes:: * , struct_span_code_err, Applicability , Diag } ;
40
40
use rustc_hir as hir;
41
41
use rustc_hir:: def_id:: DefId ;
42
- use rustc_hir:: intravisit:: { self , Visitor } ;
43
- use rustc_hir:: Expr ;
44
42
use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
45
43
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
46
44
use rustc_infer:: infer:: { Coercion , DefineOpaqueTypes , InferOk , InferResult } ;
@@ -93,22 +91,6 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
93
91
94
92
type CoerceResult < ' tcx > = InferResult < ' tcx , ( Vec < Adjustment < ' tcx > > , Ty < ' tcx > ) > ;
95
93
96
- struct CollectRetsVisitor < ' tcx > {
97
- ret_exprs : Vec < & ' tcx hir:: Expr < ' tcx > > ,
98
- }
99
-
100
- impl < ' tcx > Visitor < ' tcx > for CollectRetsVisitor < ' tcx > {
101
- fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
102
- match expr. kind {
103
- hir:: ExprKind :: Ret ( _) => self . ret_exprs . push ( expr) ,
104
- // `return` in closures does not return from the outer function
105
- hir:: ExprKind :: Closure ( _) => return ,
106
- _ => { }
107
- }
108
- intravisit:: walk_expr ( self , expr) ;
109
- }
110
- }
111
-
112
94
/// Coercing a mutable reference to an immutable works, while
113
95
/// coercing `&T` to `&mut T` should be forbidden.
114
96
fn coerce_mutbls < ' tcx > (
@@ -1591,7 +1573,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
1591
1573
1592
1574
let mut err;
1593
1575
let mut unsized_return = false ;
1594
- let mut visitor = CollectRetsVisitor { ret_exprs : vec ! [ ] } ;
1595
1576
match * cause. code ( ) {
1596
1577
ObligationCauseCode :: ReturnNoExpression => {
1597
1578
err = struct_span_code_err ! (
@@ -1617,11 +1598,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
1617
1598
if !fcx. tcx . features ( ) . unsized_locals {
1618
1599
unsized_return = self . is_return_ty_definitely_unsized ( fcx) ;
1619
1600
}
1620
- if let Some ( expression) = expression
1621
- && let hir:: ExprKind :: Loop ( loop_blk, ..) = expression. kind
1622
- {
1623
- intravisit:: walk_block ( & mut visitor, loop_blk) ;
1624
- }
1625
1601
}
1626
1602
ObligationCauseCode :: ReturnValue ( id) => {
1627
1603
err = self . report_return_mismatched_types (
@@ -1659,15 +1635,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
1659
1635
None ,
1660
1636
Some ( coercion_error) ,
1661
1637
) ;
1662
- if visitor. ret_exprs . len ( ) > 0 {
1663
- self . note_unreachable_loop_return (
1664
- & mut err,
1665
- fcx. tcx ,
1666
- & expr,
1667
- & visitor. ret_exprs ,
1668
- expected,
1669
- ) ;
1670
- }
1638
+
1639
+ self . note_unreachable_loop_return ( & mut err, fcx. tcx , & expr, expected) ;
1671
1640
}
1672
1641
1673
1642
let reported = err. emit_unless ( unsized_return) ;
@@ -1682,102 +1651,61 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
1682
1651
err : & mut Diag < ' _ > ,
1683
1652
tcx : TyCtxt < ' tcx > ,
1684
1653
expr : & hir:: Expr < ' tcx > ,
1685
- ret_exprs : & Vec < & ' tcx hir:: Expr < ' tcx > > ,
1686
1654
ty : Ty < ' tcx > ,
1687
1655
) {
1688
- let hir:: ExprKind :: Loop ( _, _, _, loop_span ) = expr. kind else {
1656
+ let hir:: ExprKind :: Loop ( _, _, _, _ ) = expr. kind else {
1689
1657
return ;
1690
1658
} ;
1691
- let mut span: MultiSpan = vec ! [ loop_span] . into ( ) ;
1692
- span. push_span_label ( loop_span, "this might have zero elements to iterate on" ) ;
1693
- const MAXITER : usize = 3 ;
1694
- let iter = ret_exprs. iter ( ) . take ( MAXITER ) ;
1695
- for ret_expr in iter {
1696
- span. push_span_label (
1697
- ret_expr. span ,
1698
- "if the loop doesn't execute, this value would never get returned" ,
1699
- ) ;
1700
- }
1701
- err. span_note (
1702
- span,
1703
- "the function expects a value to always be returned, but loops might run zero times" ,
1704
- ) ;
1705
- if MAXITER < ret_exprs. len ( ) {
1706
- err. note ( format ! (
1707
- "if the loop doesn't execute, {} other values would never get returned" ,
1708
- ret_exprs. len( ) - MAXITER
1709
- ) ) ;
1710
- }
1659
+
1711
1660
let hir = tcx. hir ( ) ;
1712
- let item = hir. get_parent_item ( expr. hir_id ) ;
1713
- let ret_msg = "return a value for the case when the loop has zero elements to iterate on" ;
1714
- let ret_ty_msg =
1715
- "otherwise consider changing the return type to account for that possibility" ;
1716
- let node = tcx. hir_node ( item. into ( ) ) ;
1717
- if let Some ( body_id) = node. body_id ( )
1718
- && let Some ( sig) = node. fn_sig ( )
1719
- && let hir:: ExprKind :: Block ( block, _) = hir. body ( body_id) . value . kind
1720
- && !ty. is_never ( )
1721
- {
1722
- let indentation = if let None = block. expr
1723
- && let [ .., last] = & block. stmts
1724
- {
1725
- tcx. sess . source_map ( ) . indentation_before ( last. span ) . unwrap_or_else ( String :: new)
1726
- } else if let Some ( expr) = block. expr {
1727
- tcx. sess . source_map ( ) . indentation_before ( expr. span ) . unwrap_or_else ( String :: new)
1661
+ let body_def_id = hir. enclosing_body_owner ( expr. hir_id ) ;
1662
+ let body_id = hir. body_owned_by ( body_def_id) ;
1663
+ let body = hir. body ( body_id) ;
1664
+
1665
+ let span = match body. value . kind {
1666
+ // Regular block as in a function body
1667
+ hir:: ExprKind :: Block ( block, _) => {
1668
+ if let None = block. expr
1669
+ && let [ .., last] = & block. stmts
1670
+ {
1671
+ Some ( last. span )
1672
+ } else if let Some ( expr) = block. expr {
1673
+ Some ( expr. span )
1674
+ } else {
1675
+ None
1676
+ }
1677
+ }
1678
+ // Anon const body (there's no enclosing block in this case)
1679
+ hir:: ExprKind :: DropTemps ( expr) => Some ( expr. span ) ,
1680
+ _ => None ,
1681
+ } ;
1682
+
1683
+ if let Some ( span) = span {
1684
+ let ( msg, suggestion) = if ty. is_never ( ) {
1685
+ (
1686
+ "consider adding a diverging expression here" ,
1687
+ "`loop {}` or `panic!(\" ...\" )`" . to_string ( ) ,
1688
+ )
1728
1689
} else {
1729
- String :: new ( )
1690
+ ( "consider returning a value here" , format ! ( "`{ty}` value" ) )
1730
1691
} ;
1731
- if let None = block. expr
1732
- && let [ .., last] = & block. stmts
1733
- {
1734
- err. span_suggestion_verbose (
1735
- last. span . shrink_to_hi ( ) ,
1736
- ret_msg,
1737
- format ! ( "\n {indentation}/* `{ty}` value */" ) ,
1738
- Applicability :: MaybeIncorrect ,
1739
- ) ;
1740
- } else if let Some ( expr) = block. expr {
1741
- err. span_suggestion_verbose (
1742
- expr. span . shrink_to_hi ( ) ,
1743
- ret_msg,
1744
- format ! ( "\n {indentation}/* `{ty}` value */" ) ,
1745
- Applicability :: MaybeIncorrect ,
1746
- ) ;
1747
- }
1748
- let mut sugg = match sig. decl . output {
1749
- hir:: FnRetTy :: DefaultReturn ( span) => {
1750
- vec ! [ ( span, " -> Option<()>" . to_string( ) ) ]
1751
- }
1752
- hir:: FnRetTy :: Return ( ty) => {
1753
- vec ! [
1754
- ( ty. span. shrink_to_lo( ) , "Option<" . to_string( ) ) ,
1755
- ( ty. span. shrink_to_hi( ) , ">" . to_string( ) ) ,
1756
- ]
1757
- }
1692
+
1693
+ let src_map = tcx. sess . source_map ( ) ;
1694
+ let suggestion = if src_map. is_multiline ( expr. span ) {
1695
+ let indentation = src_map. indentation_before ( span) . unwrap_or_else ( String :: new) ;
1696
+ format ! ( "\n {indentation}/* {suggestion} */" )
1697
+ } else {
1698
+ // If the entire expr is on a single line
1699
+ // put the suggestion also on the same line
1700
+ format ! ( " /* {suggestion} */" )
1758
1701
} ;
1759
- for ret_expr in ret_exprs {
1760
- match ret_expr. kind {
1761
- hir:: ExprKind :: Ret ( Some ( expr) ) => {
1762
- sugg. push ( ( expr. span . shrink_to_lo ( ) , "Some(" . to_string ( ) ) ) ;
1763
- sugg. push ( ( expr. span . shrink_to_hi ( ) , ")" . to_string ( ) ) ) ;
1764
- }
1765
- hir:: ExprKind :: Ret ( None ) => {
1766
- sugg. push ( ( ret_expr. span . shrink_to_hi ( ) , " Some(())" . to_string ( ) ) ) ;
1767
- }
1768
- _ => { }
1769
- }
1770
- }
1771
- if let None = block. expr
1772
- && let [ .., last] = & block. stmts
1773
- {
1774
- sugg. push ( ( last. span . shrink_to_hi ( ) , format ! ( "\n {indentation}None" ) ) ) ;
1775
- } else if let Some ( expr) = block. expr {
1776
- sugg. push ( ( expr. span . shrink_to_hi ( ) , format ! ( "\n {indentation}None" ) ) ) ;
1777
- }
1778
- err. multipart_suggestion ( ret_ty_msg, sugg, Applicability :: MaybeIncorrect ) ;
1779
- } else {
1780
- err. help ( format ! ( "{ret_msg}, {ret_ty_msg}" ) ) ;
1702
+
1703
+ err. span_suggestion_verbose (
1704
+ span. shrink_to_hi ( ) ,
1705
+ msg,
1706
+ suggestion,
1707
+ Applicability :: MaybeIncorrect ,
1708
+ ) ;
1781
1709
}
1782
1710
}
1783
1711
0 commit comments