<commit_before>use crate::check::FnCtxt;
use rustc_infer::infer::InferOk;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause;

use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::sym;
use rustc_span::{BytePos, Span};

use super::method::probe;

use std::iter;

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub fn emit_coerce_suggestions(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
        expr_ty: Ty<'tcx>,
        expected: Ty<'tcx>,
        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
    ) {
        self.annotate_expected_due_to_let_ty(err, expr);
        self.suggest_box_deref(err, expr, expected, expr_ty);
        self.suggest_compatible_variants(err, expr, expected, expr_ty);
        self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
        if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
            return;
        }
        self.suggest_no_capture_closure(err, expected, expr_ty);
        self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
        self.suggest_missing_parentheses(err, expr);
        self.note_need_for_fn_pointer(err, expected, expr_ty);
        self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
        self.report_closure_inferred_return_type(err, expected);
    }

    // Requires that the two types unify, and prints an error message if
    // they don't.
    pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
        if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
            e.emit();
        }
    }

    pub fn demand_suptype_diag(
        &self,
        sp: Span,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
    }

    #[instrument(skip(self), level = "debug")]
    pub fn demand_suptype_with_origin(
        &self,
        cause: &ObligationCause<'tcx>,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        match self.at(cause, self.param_env).sup(expected, actual) {
            Ok(InferOk { obligations, value: () }) => {
                self.register_predicates(obligations);
                None
            }
            Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
        }
    }

    pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
        if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) {
            err.emit();
        }
    }

    pub fn demand_eqtype_diag(
        &self,
        sp: Span,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
    }

    pub fn demand_eqtype_with_origin(
        &self,
        cause: &ObligationCause<'tcx>,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        match self.at(cause, self.param_env).eq(expected, actual) {
            Ok(InferOk { obligations, value: () }) => {
                self.register_predicates(obligations);
                None
            }
            Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
        }
    }

    pub fn demand_coerce(
        &self,
        expr: &hir::Expr<'_>,
        checked_ty: Ty<'tcx>,
        expected: Ty<'tcx>,
        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
        allow_two_phase: AllowTwoPhase,
    ) -> Ty<'tcx> {
        let (ty, err) =
            self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase);
        if let Some(mut err) = err {
            err.emit();
        }
        ty
    }

    /// Checks that the type of `expr` can be coerced to `expected`.
    ///
    /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
    /// will be permitted if the diverges flag is currently "always".
    pub fn demand_coerce_diag(
        &self,
        expr: &hir::Expr<'_>,
        checked_ty: Ty<'tcx>,
        expected: Ty<'tcx>,
        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
        allow_two_phase: AllowTwoPhase,
    ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
        let expected = self.resolve_vars_with_obligations(expected);

        let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
            Ok(ty) => return (ty, None),
            Err(e) => e,
        };

        self.set_tainted_by_errors();
        let expr = expr.peel_drop_temps();
        let cause = self.misc(expr.span);
        let expr_ty = self.resolve_vars_with_obligations(checked_ty);
        let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);

        self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);

        (expected, Some(err))
    }

    fn annotate_expected_due_to_let_ty(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
    ) {
        let parent = self.tcx.hir().get_parent_node(expr.hir_id);
        if let Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })) =
            self.tcx.hir().find(parent)
        {
            if init.hir_id == expr.hir_id {
                // Point at `let` assignment type.
                err.span_label(ty.span, "expected due to this");
            }
        }
    }

    fn suggest_box_deref(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
        expected: Ty<'tcx>,
        expr_ty: Ty<'tcx>,
    ) {
        if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
            err.span_suggestion_verbose(
                expr.span.shrink_to_lo(),
                "try dereferencing the `Box`",
                "*".to_string(),
                Applicability::MachineApplicable,
            );
        }
    }

    /// If the expected type is an enum (Issue #55250) with any variants whose
    /// sole field is of the found type, suggest such variants. (Issue #42764)
    fn suggest_compatible_variants(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
        expected: Ty<'tcx>,
        expr_ty: Ty<'tcx>,
    ) {
        if let ty::Adt(expected_adt, substs) = expected.kind() {
            if !expected_adt.is_enum() {
                return;
            }
<commit_msg>Improve suggestion for unit Option/Result at the end of a block.<commit_after>use crate::check::FnCtxt;
use rustc_infer::infer::InferOk;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause;

use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::sym;
use rustc_span::{BytePos, Span};

use super::method::probe;

use std::iter;

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub fn emit_coerce_suggestions(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
        expr_ty: Ty<'tcx>,
        expected: Ty<'tcx>,
        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
    ) {
        self.annotate_expected_due_to_let_ty(err, expr);
        self.suggest_box_deref(err, expr, expected, expr_ty);
        self.suggest_compatible_variants(err, expr, expected, expr_ty);
        self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
        if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
            return;
        }
        self.suggest_no_capture_closure(err, expected, expr_ty);
        self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
        self.suggest_missing_parentheses(err, expr);
        self.note_need_for_fn_pointer(err, expected, expr_ty);
        self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
        self.report_closure_inferred_return_type(err, expected);
    }

    // Requires that the two types unify, and prints an error message if
    // they don't.
    pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
        if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
            e.emit();
        }
    }

    pub fn demand_suptype_diag(
        &self,
        sp: Span,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
    }

    #[instrument(skip(self), level = "debug")]
    pub fn demand_suptype_with_origin(
        &self,
        cause: &ObligationCause<'tcx>,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        match self.at(cause, self.param_env).sup(expected, actual) {
            Ok(InferOk { obligations, value: () }) => {
                self.register_predicates(obligations);
                None
            }
            Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
        }
    }

    pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
        if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) {
            err.emit();
        }
    }

    pub fn demand_eqtype_diag(
        &self,
        sp: Span,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
    }

    pub fn demand_eqtype_with_origin(
        &self,
        cause: &ObligationCause<'tcx>,
        expected: Ty<'tcx>,
        actual: Ty<'tcx>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        match self.at(cause, self.param_env).eq(expected, actual) {
            Ok(InferOk { obligations, value: () }) => {
                self.register_predicates(obligations);
                None
            }
            Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
        }
    }

    pub fn demand_coerce(
        &self,
        expr: &hir::Expr<'_>,
        checked_ty: Ty<'tcx>,
        expected: Ty<'tcx>,
        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
        allow_two_phase: AllowTwoPhase,
    ) -> Ty<'tcx> {
        let (ty, err) =
            self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase);
        if let Some(mut err) = err {
            err.emit();
        }
        ty
    }

    /// Checks that the type of `expr` can be coerced to `expected`.
    ///
    /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
    /// will be permitted if the diverges flag is currently "always".
    pub fn demand_coerce_diag(
        &self,
        expr: &hir::Expr<'_>,
        checked_ty: Ty<'tcx>,
        expected: Ty<'tcx>,
        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
        allow_two_phase: AllowTwoPhase,
    ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
        let expected = self.resolve_vars_with_obligations(expected);

        let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
            Ok(ty) => return (ty, None),
            Err(e) => e,
        };

        self.set_tainted_by_errors();
        let expr = expr.peel_drop_temps();
        let cause = self.misc(expr.span);
        let expr_ty = self.resolve_vars_with_obligations(checked_ty);
        let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);

        self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);

        (expected, Some(err))
    }

    fn annotate_expected_due_to_let_ty(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
    ) {
        let parent = self.tcx.hir().get_parent_node(expr.hir_id);
        if let Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })) =
            self.tcx.hir().find(parent)
        {
            if init.hir_id == expr.hir_id {
                // Point at `let` assignment type.
                err.span_label(ty.span, "expected due to this");
            }
        }
    }

    fn suggest_box_deref(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
        expected: Ty<'tcx>,
        expr_ty: Ty<'tcx>,
    ) {
        if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
            err.span_suggestion_verbose(
                expr.span.shrink_to_lo(),
                "try dereferencing the `Box`",
                "*".to_string(),
                Applicability::MachineApplicable,
            );
        }
    }

    /// If the expected type is an enum (Issue #55250) with any variants whose
    /// sole field is of the found type, suggest such variants. (Issue #42764)
    fn suggest_compatible_variants(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        expr: &hir::Expr<'_>,
        expected: Ty<'tcx>,
        expr_ty: Ty<'tcx>,
    ) {
        if let ty::Adt(expected_adt, substs) = expected.kind() {
            if !expected_adt.is_enum() {
                return;
            }

            // If the expression is of type () and it's the return expression of a block,
            // we suggest adding a separate return expression instead.
            // (To avoid things like suggesting `Ok(while .. { .. })`.)
            if expr_ty.is_unit() {
                if let Some(hir::Node::Block(&hir::Block {
                    span: block_span, expr: Some(e), ..
                })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
                {
                    if e.hir_id == expr.hir_id {
                        if let Some(span) = expr.span.find_ancestor_inside(block_span) {
                            let return_suggestions =
                                if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) {
                                    vec!["Ok(())".to_string()]
                                } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did)
                                {
                                    vec!["None".to_string(), "Some(())".to_string()]
                                } else {
                                    return;
                                };
                            if let Some(indent) =
                                self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
                            {
                                // Add a semicolon, except after `}`.
                                let semicolon =
                                    match self.tcx.sess.source_map().span_to_snippet(span) {
                                        Ok(s) if s.ends_with('}') => "",
                                        _ => ";",
                                    };
                                err.multipart_suggestions(
                                    "try adding an expression at the end of the block",
                                    return_suggestions.into_iter().map(|r| {
                                        vec![(
                                            span.shrink_to_hi(),
                                            format!("{}\n{}{}", semicolon, indent, r),
                                        )]
                                    }),
                                    Applicability::MaybeIncorrect,
                                );
                            }
                            return;
                        }
                    }
                }
            }

{'fraction_non_alphanumeric': 0.12767379679144386, 'fraction_numerical': 0.0012153621779290229, 'mean_word_length': 2.018525311812179, 'pattern_counts': {'":': 0, '<': 111, '<?xml version=': 0, '>': 137, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 25, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2388639', 'n_tokens_mistral': 5183, 'n_tokens_neox': 5179, 'n_words': 1017}