|  | 
|  | 1 | +// ignore-tidy-filelength | 
| 1 | 2 | use core::cmp::min; | 
| 2 | 3 | use core::iter; | 
| 3 | 4 | 
 | 
| @@ -766,56 +767,121 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | 
| 766 | 767 |         needs_block: bool, | 
| 767 | 768 |         parent_is_closure: bool, | 
| 768 | 769 |     ) { | 
| 769 |  | -        if expected.is_unit() { | 
| 770 |  | -            // `BlockTailExpression` only relevant if the tail expr would be | 
| 771 |  | -            // useful on its own. | 
| 772 |  | -            match expression.kind { | 
| 773 |  | -                ExprKind::Call(..) | 
| 774 |  | -                | ExprKind::MethodCall(..) | 
| 775 |  | -                | ExprKind::Loop(..) | 
| 776 |  | -                | ExprKind::If(..) | 
| 777 |  | -                | ExprKind::Match(..) | 
| 778 |  | -                | ExprKind::Block(..) | 
| 779 |  | -                    if expression.can_have_side_effects() | 
| 780 |  | -                        // If the expression is from an external macro, then do not suggest | 
| 781 |  | -                        // adding a semicolon, because there's nowhere to put it. | 
| 782 |  | -                        // See issue #81943. | 
| 783 |  | -                        && !expression.span.in_external_macro(self.tcx.sess.source_map()) => | 
|  | 770 | +        if !expected.is_unit() { | 
|  | 771 | +            return; | 
|  | 772 | +        } | 
|  | 773 | +        // `BlockTailExpression` only relevant if the tail expr would be | 
|  | 774 | +        // useful on its own. | 
|  | 775 | +        match expression.kind { | 
|  | 776 | +            ExprKind::Call(..) | 
|  | 777 | +            | ExprKind::MethodCall(..) | 
|  | 778 | +            | ExprKind::Loop(..) | 
|  | 779 | +            | ExprKind::If(..) | 
|  | 780 | +            | ExprKind::Match(..) | 
|  | 781 | +            | ExprKind::Block(..) | 
|  | 782 | +                if expression.can_have_side_effects() | 
|  | 783 | +                    // If the expression is from an external macro, then do not suggest | 
|  | 784 | +                    // adding a semicolon, because there's nowhere to put it. | 
|  | 785 | +                    // See issue #81943. | 
|  | 786 | +                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) => | 
|  | 787 | +            { | 
|  | 788 | +                if needs_block { | 
|  | 789 | +                    err.multipart_suggestion( | 
|  | 790 | +                        "consider using a semicolon here", | 
|  | 791 | +                        vec![ | 
|  | 792 | +                            (expression.span.shrink_to_lo(), "{ ".to_owned()), | 
|  | 793 | +                            (expression.span.shrink_to_hi(), "; }".to_owned()), | 
|  | 794 | +                        ], | 
|  | 795 | +                        Applicability::MachineApplicable, | 
|  | 796 | +                    ); | 
|  | 797 | +                } else if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id) | 
|  | 798 | +                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id) | 
|  | 799 | +                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id) | 
|  | 800 | +                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind | 
|  | 801 | +                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id) | 
|  | 802 | +                    && let hir::StmtKind::Expr(_) = stmt.kind | 
|  | 803 | +                    && self.is_next_stmt_expr_continuation(stmt.hir_id) | 
| 784 | 804 |                 { | 
| 785 |  | -                    if needs_block { | 
| 786 |  | -                        err.multipart_suggestion( | 
| 787 |  | -                            "consider using a semicolon here", | 
| 788 |  | -                            vec![ | 
| 789 |  | -                                (expression.span.shrink_to_lo(), "{ ".to_owned()), | 
| 790 |  | -                                (expression.span.shrink_to_hi(), "; }".to_owned()), | 
| 791 |  | -                            ], | 
| 792 |  | -                            Applicability::MachineApplicable, | 
| 793 |  | -                        ); | 
| 794 |  | -                    } else { | 
| 795 |  | -                        err.span_suggestion( | 
| 796 |  | -                            expression.span.shrink_to_hi(), | 
| 797 |  | -                            "consider using a semicolon here", | 
| 798 |  | -                            ";", | 
| 799 |  | -                            Applicability::MachineApplicable, | 
| 800 |  | -                        ); | 
| 801 |  | -                    } | 
|  | 805 | +                    err.multipart_suggestion( | 
|  | 806 | +                        "parentheses are required to parse this as an expression", | 
|  | 807 | +                        vec![ | 
|  | 808 | +                            (stmt.span.shrink_to_lo(), "(".to_string()), | 
|  | 809 | +                            (stmt.span.shrink_to_hi(), ")".to_string()), | 
|  | 810 | +                        ], | 
|  | 811 | +                        Applicability::MachineApplicable, | 
|  | 812 | +                    ); | 
|  | 813 | +                } else { | 
|  | 814 | +                    err.span_suggestion( | 
|  | 815 | +                        expression.span.shrink_to_hi(), | 
|  | 816 | +                        "consider using a semicolon here", | 
|  | 817 | +                        ";", | 
|  | 818 | +                        Applicability::MachineApplicable, | 
|  | 819 | +                    ); | 
| 802 | 820 |                 } | 
| 803 |  | -                ExprKind::Path(..) | ExprKind::Lit(_) | 
| 804 |  | -                    if parent_is_closure | 
| 805 |  | -                        && !expression.span.in_external_macro(self.tcx.sess.source_map()) => | 
|  | 821 | +            } | 
|  | 822 | +            ExprKind::Path(..) | ExprKind::Lit(_) | 
|  | 823 | +                if parent_is_closure | 
|  | 824 | +                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) => | 
|  | 825 | +            { | 
|  | 826 | +                err.span_suggestion_verbose( | 
|  | 827 | +                    expression.span.shrink_to_lo(), | 
|  | 828 | +                    "consider ignoring the value", | 
|  | 829 | +                    "_ = ", | 
|  | 830 | +                    Applicability::MachineApplicable, | 
|  | 831 | +                ); | 
|  | 832 | +            } | 
|  | 833 | +            _ => { | 
|  | 834 | +                if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id) | 
|  | 835 | +                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id) | 
|  | 836 | +                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id) | 
|  | 837 | +                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind | 
|  | 838 | +                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id) | 
|  | 839 | +                    && let hir::StmtKind::Expr(_) = stmt.kind | 
|  | 840 | +                    && self.is_next_stmt_expr_continuation(stmt.hir_id) | 
| 806 | 841 |                 { | 
| 807 |  | -                    err.span_suggestion_verbose( | 
| 808 |  | -                        expression.span.shrink_to_lo(), | 
| 809 |  | -                        "consider ignoring the value", | 
| 810 |  | -                        "_ = ", | 
|  | 842 | +                    // The error is pointing at an arm of an if-expression, and we want to get the | 
|  | 843 | +                    // `Span` of the whole if-expression for the suggestion. This only works for a | 
|  | 844 | +                    // single level of nesting, which is fine. | 
|  | 845 | +                    // We have something like `if true { false } else { true } && true`. Suggest | 
|  | 846 | +                    // wrapping in parentheses. We find the statement or expression following the | 
|  | 847 | +                    // `if` (`&& true`) and see if it is something that can reasonably be | 
|  | 848 | +                    // interpreted as a binop following an expression. | 
|  | 849 | +                    err.multipart_suggestion( | 
|  | 850 | +                        "parentheses are required to parse this as an expression", | 
|  | 851 | +                        vec![ | 
|  | 852 | +                            (stmt.span.shrink_to_lo(), "(".to_string()), | 
|  | 853 | +                            (stmt.span.shrink_to_hi(), ")".to_string()), | 
|  | 854 | +                        ], | 
| 811 | 855 |                         Applicability::MachineApplicable, | 
| 812 | 856 |                     ); | 
| 813 | 857 |                 } | 
| 814 |  | -                _ => (), | 
| 815 | 858 |             } | 
| 816 | 859 |         } | 
| 817 | 860 |     } | 
| 818 | 861 | 
 | 
|  | 862 | +    pub(crate) fn is_next_stmt_expr_continuation(&self, hir_id: HirId) -> bool { | 
|  | 863 | +        if let hir::Node::Block(b) = self.tcx.parent_hir_node(hir_id) | 
|  | 864 | +            && let mut stmts = b.stmts.iter().skip_while(|s| s.hir_id != hir_id) | 
|  | 865 | +            && let Some(_) = stmts.next() // The statement the statement that was passed in | 
|  | 866 | +            && let Some(next) = match (stmts.next(), b.expr) { // The following statement | 
|  | 867 | +                (Some(next), _) => match next.kind { | 
|  | 868 | +                    hir::StmtKind::Expr(next) | hir::StmtKind::Semi(next) => Some(next), | 
|  | 869 | +                    _ => None, | 
|  | 870 | +                }, | 
|  | 871 | +                (None, Some(next)) => Some(next), | 
|  | 872 | +                _ => None, | 
|  | 873 | +            } | 
|  | 874 | +            && let hir::ExprKind::AddrOf(..) // prev_stmt && next | 
|  | 875 | +                | hir::ExprKind::Unary(..) // prev_stmt * next | 
|  | 876 | +                | hir::ExprKind::Err(_) = next.kind | 
|  | 877 | +        // prev_stmt + next | 
|  | 878 | +        { | 
|  | 879 | +            true | 
|  | 880 | +        } else { | 
|  | 881 | +            false | 
|  | 882 | +        } | 
|  | 883 | +    } | 
|  | 884 | + | 
| 819 | 885 |     /// A possible error is to forget to add a return type that is needed: | 
| 820 | 886 |     /// | 
| 821 | 887 |     /// ```compile_fail,E0308 | 
|  | 
0 commit comments