]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_infer/src/infer/error_reporting/mod.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / mod.rs
index 9ff703e521ff666aa5b2a44d8bb0effe9b776725..987559d7e47243ead6b12e2762ae7716b0d41010 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 //! Error Reporting Code for the inference engine
 //!
 //! Because of the way inference, and in particular region inference,
@@ -55,10 +56,9 @@ use crate::infer::ExpectedFound;
 use crate::traits::error_reporting::report_object_safety_error;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
-    StatementAsExpression,
 };
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
 use rustc_hir as hir;
@@ -67,18 +67,19 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Node;
 use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
 use rustc_middle::ty::{
-    self, error::TypeError, Binder, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
     TypeVisitable,
 };
 use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::{ControlFlow, Deref};
+use std::path::PathBuf;
 use std::{cmp, fmt, iter};
 
 mod note;
+mod suggest;
 
 pub(crate) mod need_type_info;
 pub use need_type_info::TypeAnnotationNeeded;
@@ -91,6 +92,8 @@ pub mod nice_region_error;
 pub struct TypeErrCtxt<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'tcx>,
     pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
+    pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
+    pub fallback_has_occurred: bool,
 }
 
 impl TypeErrCtxt<'_, '_> {
@@ -206,9 +209,12 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
                         };
                         (text, sp)
                     }
-                    ty::BrAnon(idx) => (
+                    ty::BrAnon(idx, span) => (
                         format!("the anonymous lifetime #{} defined here", idx + 1),
-                        tcx.def_span(scope)
+                        match span {
+                            Some(span) => span,
+                            None => tcx.def_span(scope)
+                        }
                     ),
                     _ => (
                         format!("the lifetime `{}` as defined here", region),
@@ -253,6 +259,7 @@ fn label_msg_span(
     }
 }
 
+#[instrument(level = "trace", skip(tcx))]
 pub fn unexpected_hidden_region_diagnostic<'tcx>(
     tcx: TyCtxt<'tcx>,
     span: Span,
@@ -330,33 +337,36 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
 }
 
 impl<'tcx> InferCtxt<'tcx> {
-    pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
-        if let ty::Opaque(def_id, substs) = ty.kind() {
-            let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
-            // Future::Output
-            let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
+    pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+        let (def_id, substs) = match *ty.kind() {
+            ty::Opaque(def_id, substs) => (def_id, substs),
+            ty::Projection(data)
+                if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
+            {
+                (data.item_def_id, data.substs)
+            }
+            _ => return None,
+        };
 
-            let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
+        let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+        let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
 
-            for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) {
-                let output = predicate
+        self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map(
+            |(predicate, _)| {
+                predicate
                     .kind()
                     .map_bound(|kind| match kind {
-                        ty::PredicateKind::Projection(projection_predicate)
+                        ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate))
                             if projection_predicate.projection_ty.item_def_id == item_def_id =>
                         {
                             projection_predicate.term.ty()
                         }
                         _ => None,
                     })
-                    .transpose();
-                if output.is_some() {
-                    // We don't account for multiple `Future::Output = Ty` constraints.
-                    return output;
-                }
-            }
-        }
-        None
+                    .no_bound_vars()
+                    .flatten()
+            },
+        )
     }
 }
 
@@ -534,7 +544,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
             fn print_dyn_existential(
                 self,
-                _predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+                _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
             ) -> Result<Self::DynExistential, Self::Error> {
                 Err(NonTrivialPath)
             }
@@ -793,87 +803,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
-    fn suggest_remove_semi_or_return_binding(
-        &self,
-        err: &mut Diagnostic,
-        first_id: Option<hir::HirId>,
-        first_ty: Ty<'tcx>,
-        first_span: Span,
-        second_id: Option<hir::HirId>,
-        second_ty: Ty<'tcx>,
-        second_span: Span,
-    ) {
-        let remove_semicolon = [
-            (first_id, self.resolve_vars_if_possible(second_ty)),
-            (second_id, self.resolve_vars_if_possible(first_ty)),
-        ]
-        .into_iter()
-        .find_map(|(id, ty)| {
-            let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None };
-            self.could_remove_semicolon(blk, ty)
-        });
-        match remove_semicolon {
-            Some((sp, StatementAsExpression::NeedsBoxing)) => {
-                err.multipart_suggestion(
-                    "consider removing this semicolon and boxing the expressions",
-                    vec![
-                        (first_span.shrink_to_lo(), "Box::new(".to_string()),
-                        (first_span.shrink_to_hi(), ")".to_string()),
-                        (second_span.shrink_to_lo(), "Box::new(".to_string()),
-                        (second_span.shrink_to_hi(), ")".to_string()),
-                        (sp, String::new()),
-                    ],
-                    Applicability::MachineApplicable,
-                );
-            }
-            Some((sp, StatementAsExpression::CorrectType)) => {
-                err.span_suggestion_short(
-                    sp,
-                    "consider removing this semicolon",
-                    "",
-                    Applicability::MachineApplicable,
-                );
-            }
-            None => {
-                for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
-                    if let Some(id) = id
-                        && let hir::Node::Block(blk) = self.tcx.hir().get(id)
-                        && self.consider_returning_binding(blk, ty, err)
-                    {
-                        break;
-                    }
-                }
-            }
-        }
-    }
-
-    fn suggest_boxing_for_return_impl_trait(
-        &self,
-        err: &mut Diagnostic,
-        return_sp: Span,
-        arm_spans: impl Iterator<Item = Span>,
-    ) {
-        err.multipart_suggestion(
-            "you could change the return type to be a boxed trait object",
-            vec![
-                (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
-                (return_sp.shrink_to_hi(), ">".to_string()),
-            ],
-            Applicability::MaybeIncorrect,
-        );
-        let sugg = arm_spans
-            .flat_map(|sp| {
-                [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
-                    .into_iter()
-            })
-            .collect::<Vec<_>>();
-        err.multipart_suggestion(
-            "if you change the return type to expect trait objects, box the returned expressions",
-            sugg,
-            Applicability::MaybeIncorrect,
-        );
-    }
-
     /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
     /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
     /// populate `other_value` with `other_ty`.
@@ -1003,22 +932,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
-    fn normalize_fn_sig_for_diagnostic(&self, sig: ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> {
-        if let Some(normalize) = &self.normalize_fn_sig_for_diagnostic {
-            normalize(self, sig)
-        } else {
-            sig
-        }
-    }
-
     /// Given two `fn` signatures highlight only sub-parts that are different.
     fn cmp_fn_sig(
         &self,
         sig1: &ty::PolyFnSig<'tcx>,
         sig2: &ty::PolyFnSig<'tcx>,
     ) -> (DiagnosticStyledString, DiagnosticStyledString) {
-        let sig1 = &self.normalize_fn_sig_for_diagnostic(*sig1);
-        let sig2 = &self.normalize_fn_sig_for_diagnostic(*sig2);
+        let sig1 = &(self.normalize_fn_sig)(*sig1);
+        let sig2 = &(self.normalize_fn_sig)(*sig2);
 
         let get_lifetimes = |sig| {
             use rustc_hir::def::Namespace;
@@ -1258,7 +1179,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     let num_display_types = consts_offset - regions_len;
                     for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
                         let i = i + regions_len;
-                        if ta1 == ta2 {
+                        if ta1 == ta2 && !self.tcx.sess.verbose() {
                             values.0.push_normal("_");
                             values.1.push_normal("_");
                         } else {
@@ -1274,7 +1195,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     let const_arguments = sub1.consts().zip(sub2.consts());
                     for (i, (ca1, ca2)) in const_arguments.enumerate() {
                         let i = i + consts_offset;
-                        if ca1 == ca2 {
+                        if ca1 == ca2 && !self.tcx.sess.verbose() {
                             values.0.push_normal("_");
                             values.1.push_normal("_");
                         } else {
@@ -1347,10 +1268,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             .map(|(mod_str, _)| mod_str.len() + separator_len)
                             .sum();
 
-                    debug!(
-                        "cmp: separator_len={}, split_idx={}, min_len={}",
-                        separator_len, split_idx, min_len
-                    );
+                    debug!(?separator_len, ?split_idx, ?min_len, "cmp");
 
                     if split_idx >= min_len {
                         // paths are identical, highlight everything
@@ -1361,7 +1279,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     } else {
                         let (common, uniq1) = t1_str.split_at(split_idx);
                         let (_, uniq2) = t2_str.split_at(split_idx);
-                        debug!("cmp: common={}, uniq1={}, uniq2={}", common, uniq1, uniq2);
+                        debug!(?common, ?uniq1, ?uniq2, "cmp");
 
                         values.0.push_normal(common);
                         values.0.push_highlighted(uniq1);
@@ -1453,7 +1371,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             (ty::FnPtr(sig1), ty::FnPtr(sig2)) => self.cmp_fn_sig(sig1, sig2),
 
             _ => {
-                if t1 == t2 {
+                if t1 == t2 && !self.tcx.sess.verbose() {
                     // The two types are the same, elide and don't highlight.
                     (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_"))
                 } else {
@@ -1498,9 +1416,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             values = None;
         }
         struct OpaqueTypesVisitor<'tcx> {
-            types: FxHashMap<TyCategory, FxHashSet<Span>>,
-            expected: FxHashMap<TyCategory, FxHashSet<Span>>,
-            found: FxHashMap<TyCategory, FxHashSet<Span>>,
+            types: FxIndexMap<TyCategory, FxIndexSet<Span>>,
+            expected: FxIndexMap<TyCategory, FxIndexSet<Span>>,
+            found: FxIndexMap<TyCategory, FxIndexSet<Span>>,
             ignore_span: Span,
             tcx: TyCtxt<'tcx>,
         }
@@ -1538,7 +1456,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 &self,
                 err: &mut Diagnostic,
                 target: &str,
-                types: &FxHashMap<TyCategory, FxHashSet<Span>>,
+                types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
             ) {
                 for (key, values) in types.iter() {
                     let count = values.len();
@@ -1654,55 +1572,46 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     }
                     ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
                 };
-                let vals = match self.values_str(values) {
-                    Some((expected, found)) => Some((expected, found)),
-                    None => {
-                        // Derived error. Cancel the emitter.
-                        // NOTE(eddyb) this was `.cancel()`, but `diag`
-                        // is borrowed, so we can't fully defuse it.
-                        diag.downgrade_to_delayed_bug();
-                        return;
-                    }
+                let Some(vals) = self.values_str(values) else {
+                    // Derived error. Cancel the emitter.
+                    // NOTE(eddyb) this was `.cancel()`, but `diag`
+                    // is borrowed, so we can't fully defuse it.
+                    diag.downgrade_to_delayed_bug();
+                    return;
                 };
-                (vals, exp_found, is_simple_error, Some(values))
+                (Some(vals), exp_found, is_simple_error, Some(values))
             }
         };
 
-        match terr {
-            // Ignore msg for object safe coercion
-            // since E0038 message will be printed
-            TypeError::ObjectUnsafeCoercion(_) => {}
-            _ => {
-                let mut label_or_note = |span: Span, msg: &str| {
-                    if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
-                        diag.span_label(span, msg);
-                    } else {
-                        diag.span_note(span, msg);
-                    }
-                };
-                if let Some((sp, msg)) = secondary_span {
-                    if swap_secondary_and_primary {
-                        let terr = if let Some(infer::ValuePairs::Terms(infer::ExpectedFound {
-                            expected,
-                            ..
-                        })) = values
-                        {
-                            format!("expected this to be `{}`", expected)
-                        } else {
-                            terr.to_string()
-                        };
-                        label_or_note(sp, &terr);
-                        label_or_note(span, &msg);
-                    } else {
-                        label_or_note(span, &terr.to_string());
-                        label_or_note(sp, &msg);
-                    }
-                } else {
-                    label_or_note(span, &terr.to_string());
-                }
+        let mut label_or_note = |span: Span, msg: &str| {
+            if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
+                diag.span_label(span, msg);
+            } else {
+                diag.span_note(span, msg);
             }
         };
-        if let Some((expected, found)) = expected_found {
+        if let Some((sp, msg)) = secondary_span {
+            if swap_secondary_and_primary {
+                let terr = if let Some(infer::ValuePairs::Terms(infer::ExpectedFound {
+                    expected,
+                    ..
+                })) = values
+                {
+                    format!("expected this to be `{}`", expected)
+                } else {
+                    terr.to_string()
+                };
+                label_or_note(sp, &terr);
+                label_or_note(span, &msg);
+            } else {
+                label_or_note(span, &terr.to_string());
+                label_or_note(sp, &msg);
+            }
+        } else {
+            label_or_note(span, &terr.to_string());
+        }
+
+        if let Some((expected, found, exp_p, found_p)) = expected_found {
             let (expected_label, found_label, exp_found) = match exp_found {
                 Mismatch::Variable(ef) => (
                     ef.expected.prefix_string(self.tcx),
@@ -1819,32 +1728,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
                 TypeError::Sorts(values) => {
                     let extra = expected == found;
-                    let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
-                        (true, ty::Opaque(def_id, _)) => {
-                            let sm = self.tcx.sess.source_map();
-                            let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
-                            format!(
-                                " (opaque type at <{}:{}:{}>)",
-                                sm.filename_for_diagnostics(&pos.file.name),
-                                pos.line,
-                                pos.col.to_usize() + 1,
-                            )
-                        }
-                        (true, ty::Projection(proj))
-                            if self.tcx.def_kind(proj.item_def_id)
-                                == DefKind::ImplTraitPlaceholder =>
-                        {
-                            let sm = self.tcx.sess.source_map();
-                            let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
-                            format!(
-                                " (trait associated opaque type at <{}:{}:{}>)",
-                                sm.filename_for_diagnostics(&pos.file.name),
-                                pos.line,
-                                pos.col.to_usize() + 1,
-                            )
+                    let sort_string = |ty: Ty<'tcx>, path: Option<PathBuf>| {
+                        let mut s = match (extra, ty.kind()) {
+                            (true, ty::Opaque(def_id, _)) => {
+                                let sm = self.tcx.sess.source_map();
+                                let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
+                                format!(
+                                    " (opaque type at <{}:{}:{}>)",
+                                    sm.filename_for_diagnostics(&pos.file.name),
+                                    pos.line,
+                                    pos.col.to_usize() + 1,
+                                )
+                            }
+                            (true, ty::Projection(proj))
+                                if self.tcx.def_kind(proj.item_def_id)
+                                    == DefKind::ImplTraitPlaceholder =>
+                            {
+                                let sm = self.tcx.sess.source_map();
+                                let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
+                                format!(
+                                    " (trait associated opaque type at <{}:{}:{}>)",
+                                    sm.filename_for_diagnostics(&pos.file.name),
+                                    pos.line,
+                                    pos.col.to_usize() + 1,
+                                )
+                            }
+                            (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
+                            (false, _) => "".to_string(),
+                        };
+                        if let Some(path) = path {
+                            s.push_str(&format!(
+                                "\nthe full type name has been written to '{}'",
+                                path.display(),
+                            ));
                         }
-                        (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
-                        (false, _) => "".to_string(),
+                        s
                     };
                     if !(values.expected.is_simple_text() && values.found.is_simple_text())
                         || (exp_found.map_or(false, |ef| {
@@ -1866,14 +1784,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             expected,
                             &found_label,
                             found,
-                            &sort_string(values.expected),
-                            &sort_string(values.found),
+                            &sort_string(values.expected, exp_p),
+                            &sort_string(values.found, found_p),
                         );
                     }
                 }
-                TypeError::ObjectUnsafeCoercion(_) => {
-                    diag.note_unsuccessful_coercion(found, expected);
-                }
                 _ => {
                     debug!(
                         "note_type_err: exp_found={:?}, expected={:?} found={:?}",
@@ -1944,310 +1859,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         debug!(?diag);
     }
 
-    fn suggest_tuple_pattern(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
-        // some modifications due to that being in typeck and this being in infer.
-        if let ObligationCauseCode::Pattern { .. } = cause.code() {
-            if let ty::Adt(expected_adt, substs) = exp_found.expected.kind() {
-                let compatible_variants: Vec<_> = expected_adt
-                    .variants()
-                    .iter()
-                    .filter(|variant| {
-                        variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
-                    })
-                    .filter_map(|variant| {
-                        let sole_field = &variant.fields[0];
-                        let sole_field_ty = sole_field.ty(self.tcx, substs);
-                        if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
-                            let variant_path =
-                                with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
-                            // FIXME #56861: DRYer prelude filtering
-                            if let Some(path) = variant_path.strip_prefix("std::prelude::") {
-                                if let Some((_, path)) = path.split_once("::") {
-                                    return Some(path.to_string());
-                                }
-                            }
-                            Some(variant_path)
-                        } else {
-                            None
-                        }
-                    })
-                    .collect();
-                match &compatible_variants[..] {
-                    [] => {}
-                    [variant] => {
-                        diag.multipart_suggestion_verbose(
-                            &format!("try wrapping the pattern in `{}`", variant),
-                            vec![
-                                (cause.span.shrink_to_lo(), format!("{}(", variant)),
-                                (cause.span.shrink_to_hi(), ")".to_string()),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                    _ => {
-                        // More than one matching variant.
-                        diag.multipart_suggestions(
-                            &format!(
-                                "try wrapping the pattern in a variant of `{}`",
-                                self.tcx.def_path_str(expected_adt.did())
-                            ),
-                            compatible_variants.into_iter().map(|variant| {
-                                vec![
-                                    (cause.span.shrink_to_lo(), format!("{}(", variant)),
-                                    (cause.span.shrink_to_hi(), ")".to_string()),
-                                ]
-                            }),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    /// A possible error is to forget to add `.await` when using futures:
-    ///
-    /// ```compile_fail,E0308
-    /// async fn make_u32() -> u32 {
-    ///     22
-    /// }
-    ///
-    /// fn take_u32(x: u32) {}
-    ///
-    /// async fn foo() {
-    ///     let x = make_u32();
-    ///     take_u32(x);
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
-    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
-    /// `.await` to the tail of the expression.
-    fn suggest_await_on_expect_found(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        exp_span: Span,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        debug!(
-            "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
-            exp_span, exp_found.expected, exp_found.found,
-        );
-
-        if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() {
-            return;
-        }
-
-        match (
-            self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder),
-            self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder),
-        ) {
-            (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause
-                .code()
-            {
-                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
-                    let then_span = self.find_block_span_from_hir_id(*then_id);
-                    diag.multipart_suggestion(
-                        "consider `await`ing on both `Future`s",
-                        vec![
-                            (then_span.shrink_to_hi(), ".await".to_string()),
-                            (exp_span.shrink_to_hi(), ".await".to_string()),
-                        ],
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                    prior_arms,
-                    ..
-                }) => {
-                    if let [.., arm_span] = &prior_arms[..] {
-                        diag.multipart_suggestion(
-                            "consider `await`ing on both `Future`s",
-                            vec![
-                                (arm_span.shrink_to_hi(), ".await".to_string()),
-                                (exp_span.shrink_to_hi(), ".await".to_string()),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        diag.help("consider `await`ing on both `Future`s");
-                    }
-                }
-                _ => {
-                    diag.help("consider `await`ing on both `Future`s");
-                }
-            },
-            (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
-                diag.span_suggestion_verbose(
-                    exp_span.shrink_to_hi(),
-                    "consider `await`ing on the `Future`",
-                    ".await",
-                    Applicability::MaybeIncorrect,
-                );
-            }
-            (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
-            {
-                ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
-                    diag.span_suggestion_verbose(
-                        then_span.shrink_to_hi(),
-                        "consider `await`ing on the `Future`",
-                        ".await",
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
-                    let then_span = self.find_block_span_from_hir_id(*then_id);
-                    diag.span_suggestion_verbose(
-                        then_span.shrink_to_hi(),
-                        "consider `await`ing on the `Future`",
-                        ".await",
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                    ref prior_arms,
-                    ..
-                }) => {
-                    diag.multipart_suggestion_verbose(
-                        "consider `await`ing on the `Future`",
-                        prior_arms
-                            .iter()
-                            .map(|arm| (arm.shrink_to_hi(), ".await".to_string()))
-                            .collect(),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                _ => {}
-            },
-            _ => {}
-        }
-    }
-
-    fn suggest_accessing_field_where_appropriate(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        debug!(
-            "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})",
-            cause, exp_found
-        );
-        if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() {
-            if expected_def.is_enum() {
-                return;
-            }
-
-            if let Some((name, ty)) = expected_def
-                .non_enum_variant()
-                .fields
-                .iter()
-                .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
-                .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
-                .find(|(_, ty)| self.same_type_modulo_infer(*ty, exp_found.found))
-            {
-                if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
-                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                        let suggestion = if expected_def.is_struct() {
-                            format!("{}.{}", snippet, name)
-                        } else if expected_def.is_union() {
-                            format!("unsafe {{ {}.{} }}", snippet, name)
-                        } else {
-                            return;
-                        };
-                        diag.span_suggestion(
-                            span,
-                            &format!(
-                                "you might have meant to use field `{}` whose type is `{}`",
-                                name, ty
-                            ),
-                            suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
-    /// suggests it.
-    fn suggest_as_ref_where_appropriate(
-        &self,
-        span: Span,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
-            && let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
-        {
-            diag.span_suggestion(
-                span,
-                msg,
-                // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
-                format!("{}.as_ref()", snippet.trim_start_matches('&')),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
-        if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
-            (expected.kind(), found.kind())
-        {
-            if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
-                if exp_def == &found_def {
-                    let have_as_ref = &[
-                        (
-                            sym::Option,
-                            "you can convert from `&Option<T>` to `Option<&T>` using \
-                        `.as_ref()`",
-                        ),
-                        (
-                            sym::Result,
-                            "you can convert from `&Result<T, E>` to \
-                        `Result<&T, &E>` using `.as_ref()`",
-                        ),
-                    ];
-                    if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
-                        self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
-                    }) {
-                        let mut show_suggestion = true;
-                        for (exp_ty, found_ty) in
-                            iter::zip(exp_substs.types(), found_substs.types())
-                        {
-                            match *exp_ty.kind() {
-                                ty::Ref(_, exp_ty, _) => {
-                                    match (exp_ty.kind(), found_ty.kind()) {
-                                        (_, ty::Param(_))
-                                        | (_, ty::Infer(_))
-                                        | (ty::Param(_), _)
-                                        | (ty::Infer(_), _) => {}
-                                        _ if self.same_type_modulo_infer(exp_ty, found_ty) => {}
-                                        _ => show_suggestion = false,
-                                    };
-                                }
-                                ty::Param(_) | ty::Infer(_) => {}
-                                _ => show_suggestion = false,
-                            }
-                        }
-                        if show_suggestion {
-                            return Some(*msg);
-                        }
-                    }
-                }
-            }
-        }
-        None
-    }
-
     pub fn report_and_explain_type_error(
         &self,
         trace: TypeTrace<'tcx>,
@@ -2332,13 +1943,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 }
                             }
                         }
+                        // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
+                        // we try to suggest to add the missing `let` for `if let Some(..) = expr`
+                        (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
+                            self.suggest_let_for_letchains(&mut err, &trace.cause, span);
+                        }
                         _ => {}
                     }
                 }
                 let code = trace.cause.code();
                 if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
                     && let hir::MatchSource::TryDesugar = source
-                    && let Some((expected_ty, found_ty)) = self.values_str(trace.values)
+                    && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
                 {
                     err.note(&format!(
                         "`?` operator cannot convert from `{}` to `{}`",
@@ -2393,7 +2009,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn values_str(
         &self,
         values: ValuePairs<'tcx>,
-    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
+    {
         match values {
             infer::Regions(exp_found) => self.expected_found_str(exp_found),
             infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
@@ -2403,7 +2020,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     found: exp_found.found.print_only_trait_path(),
                 };
                 match self.expected_found_str(pretty_exp_found) {
-                    Some((expected, found)) if expected == found => {
+                    Some((expected, found, _, _)) if expected == found => {
                         self.expected_found_str(exp_found)
                     }
                     ret => ret,
@@ -2415,7 +2032,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     found: exp_found.found.print_only_trait_path(),
                 };
                 match self.expected_found_str(pretty_exp_found) {
-                    Some((expected, found)) if expected == found => {
+                    Some((expected, found, _, _)) if expected == found => {
                         self.expected_found_str(exp_found)
                     }
                     ret => ret,
@@ -2427,17 +2044,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn expected_found_str_term(
         &self,
         exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
-    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
+    {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
         }
 
         Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
-            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
+            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
+                let (mut exp, mut fnd) = self.cmp(expected, found);
+                // Use the terminal width as the basis to determine when to compress the printed
+                // out type, but give ourselves some leeway to avoid ending up creating a file for
+                // a type that is somewhat shorter than the path we'd write to.
+                let len = self.tcx.sess().diagnostic_width() + 40;
+                let exp_s = exp.content();
+                let fnd_s = fnd.content();
+                let mut exp_p = None;
+                let mut fnd_p = None;
+                if exp_s.len() > len {
+                    let (exp_s, exp_path) = self.tcx.short_ty_string(expected);
+                    exp = DiagnosticStyledString::highlighted(exp_s);
+                    exp_p = exp_path;
+                }
+                if fnd_s.len() > len {
+                    let (fnd_s, fnd_path) = self.tcx.short_ty_string(found);
+                    fnd = DiagnosticStyledString::highlighted(fnd_s);
+                    fnd_p = fnd_path;
+                }
+                (exp, fnd, exp_p, fnd_p)
+            }
             _ => (
                 DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
                 DiagnosticStyledString::highlighted(exp_found.found.to_string()),
+                None,
+                None,
             ),
         })
     }
@@ -2446,7 +2087,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         &self,
         exp_found: ty::error::ExpectedFound<T>,
-    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
+    {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
@@ -2455,6 +2097,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         Some((
             DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
             DiagnosticStyledString::highlighted(exp_found.found.to_string()),
+            None,
+            None,
         ))
     }
 
@@ -2788,36 +2432,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
         debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
 
-        if let (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) =
-            (&sup_origin, &sub_origin)
+        if let infer::Subtype(ref sup_trace) = sup_origin
+            && let infer::Subtype(ref sub_trace) = sub_origin
+            && let Some((sup_expected, sup_found, _, _)) = self.values_str(sup_trace.values)
+            && let Some((sub_expected, sub_found, _, _)) = self.values_str(sub_trace.values)
+            && sub_expected == sup_expected
+            && sub_found == sup_found
         {
-            debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace);
-            debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace);
-            debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values);
-            debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values);
-
-            if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) =
-                (self.values_str(sup_trace.values), self.values_str(sub_trace.values))
-            {
-                if sub_expected == sup_expected && sub_found == sup_found {
-                    note_and_explain_region(
-                        self.tcx,
-                        &mut err,
-                        "...but the lifetime must also be valid for ",
-                        sub_region,
-                        "...",
-                        None,
-                    );
-                    err.span_note(
-                        sup_trace.cause.span,
-                        &format!("...so that the {}", sup_trace.cause.as_requirement_str()),
-                    );
+            note_and_explain_region(
+                self.tcx,
+                &mut err,
+                "...but the lifetime must also be valid for ",
+                sub_region,
+                "...",
+                None,
+            );
+            err.span_note(
+                sup_trace.cause.span,
+                &format!("...so that the {}", sup_trace.cause.as_requirement_str()),
+            );
 
-                    err.note_expected_found(&"", sup_expected, &"", sup_found);
-                    err.emit();
-                    return;
-                }
-            }
+            err.note_expected_found(&"", sup_expected, &"", sup_found);
+            err.emit();
+            return;
         }
 
         self.note_region_origin(&mut err, &sup_origin);
@@ -2862,6 +2499,11 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
         self.0.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.0.intercrate);
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         // Unused, only for consts which we treat as always equal
         ty::ParamEnv::empty()
@@ -2875,6 +2517,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: relate::Relate<'tcx>>(
         &mut self,
         _variance: ty::Variance,
@@ -3043,7 +2689,6 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
                 TypeError::IntrinsicCast => {
                     Error0308("cannot coerce intrinsics to function pointers")
                 }
-                TypeError::ObjectUnsafeCoercion(did) => Error0038(did),
                 _ => Error0308("mismatched types"),
             },
         }
@@ -3158,211 +2803,3 @@ impl<'tcx> InferCtxt<'tcx> {
         }
     }
 }
-
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
-    /// Be helpful when the user wrote `{... expr; }` and taking the `;` off
-    /// is enough to fix the error.
-    pub fn could_remove_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-    ) -> Option<(Span, StatementAsExpression)> {
-        let blk = blk.innermost_block();
-        // Do not suggest if we have a tail expr.
-        if blk.expr.is_some() {
-            return None;
-        }
-        let last_stmt = blk.stmts.last()?;
-        let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
-            return None;
-        };
-        let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?;
-        let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
-            _ if last_expr_ty.references_error() => return None,
-            _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
-                StatementAsExpression::CorrectType
-            }
-            (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
-                if last_def_id == exp_def_id =>
-            {
-                StatementAsExpression::CorrectType
-            }
-            (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
-                debug!(
-                    "both opaque, likely future {:?} {:?} {:?} {:?}",
-                    last_def_id, last_bounds, exp_def_id, exp_bounds
-                );
-
-                let last_local_id = last_def_id.as_local()?;
-                let exp_local_id = exp_def_id.as_local()?;
-
-                match (
-                    &self.tcx.hir().expect_item(last_local_id).kind,
-                    &self.tcx.hir().expect_item(exp_local_id).kind,
-                ) {
-                    (
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
-                    ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| {
-                        match (left, right) {
-                            (
-                                hir::GenericBound::Trait(tl, ml),
-                                hir::GenericBound::Trait(tr, mr),
-                            ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
-                                && ml == mr =>
-                            {
-                                true
-                            }
-                            (
-                                hir::GenericBound::LangItemTrait(langl, _, _, argsl),
-                                hir::GenericBound::LangItemTrait(langr, _, _, argsr),
-                            ) if langl == langr => {
-                                // FIXME: consider the bounds!
-                                debug!("{:?} {:?}", argsl, argsr);
-                                true
-                            }
-                            _ => false,
-                        }
-                    }) =>
-                    {
-                        StatementAsExpression::NeedsBoxing
-                    }
-                    _ => StatementAsExpression::CorrectType,
-                }
-            }
-            _ => return None,
-        };
-        let span = if last_stmt.span.from_expansion() {
-            let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span);
-            self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
-        } else {
-            last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
-        };
-        Some((span, needs_box))
-    }
-
-    /// Suggest returning a local binding with a compatible type if the block
-    /// has no return expression.
-    pub fn consider_returning_binding(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-        err: &mut Diagnostic,
-    ) -> bool {
-        let blk = blk.innermost_block();
-        // Do not suggest if we have a tail expr.
-        if blk.expr.is_some() {
-            return false;
-        }
-        let mut shadowed = FxHashSet::default();
-        let mut candidate_idents = vec![];
-        let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
-            if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
-                && let Some(pat_ty) = self
-                    .typeck_results
-                    .as_ref()
-                    .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id))
-            {
-                let pat_ty = self.resolve_vars_if_possible(pat_ty);
-                if self.same_type_modulo_infer(pat_ty, expected_ty)
-                    && !(pat_ty, expected_ty).references_error()
-                    && shadowed.insert(ident.name)
-                {
-                    candidate_idents.push((*ident, pat_ty));
-                }
-            }
-            true
-        };
-
-        let hir = self.tcx.hir();
-        for stmt in blk.stmts.iter().rev() {
-            let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
-            local.pat.walk(&mut find_compatible_candidates);
-        }
-        match hir.find(hir.get_parent_node(blk.hir_id)) {
-            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
-                match hir.find(hir.get_parent_node(*hir_id)) {
-                    Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
-                        pat.walk(&mut find_compatible_candidates);
-                    }
-                    Some(
-                        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
-                        | hir::Node::ImplItem(hir::ImplItem {
-                            kind: hir::ImplItemKind::Fn(_, body),
-                            ..
-                        })
-                        | hir::Node::TraitItem(hir::TraitItem {
-                            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
-                            ..
-                        })
-                        | hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
-                            ..
-                        }),
-                    ) => {
-                        for param in hir.body(*body).params {
-                            param.pat.walk(&mut find_compatible_candidates);
-                        }
-                    }
-                    Some(hir::Node::Expr(hir::Expr {
-                        kind:
-                            hir::ExprKind::If(
-                                hir::Expr { kind: hir::ExprKind::Let(let_), .. },
-                                then_block,
-                                _,
-                            ),
-                        ..
-                    })) if then_block.hir_id == *hir_id => {
-                        let_.pat.walk(&mut find_compatible_candidates);
-                    }
-                    _ => {}
-                }
-            }
-            _ => {}
-        }
-
-        match &candidate_idents[..] {
-            [(ident, _ty)] => {
-                let sm = self.tcx.sess.source_map();
-                if let Some(stmt) = blk.stmts.last() {
-                    let stmt_span = sm.stmt_span(stmt.span, blk.span);
-                    let sugg = if sm.is_multiline(blk.span)
-                        && let Some(spacing) = sm.indentation_before(stmt_span)
-                    {
-                        format!("\n{spacing}{ident}")
-                    } else {
-                        format!(" {ident}")
-                    };
-                    err.span_suggestion_verbose(
-                        stmt_span.shrink_to_hi(),
-                        format!("consider returning the local binding `{ident}`"),
-                        sugg,
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    let sugg = if sm.is_multiline(blk.span)
-                        && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
-                    {
-                        format!("\n{spacing}    {ident}\n{spacing}")
-                    } else {
-                        format!(" {ident} ")
-                    };
-                    let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
-                    err.span_suggestion_verbose(
-                        sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
-                        format!("consider returning the local binding `{ident}`"),
-                        sugg,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                true
-            }
-            values if (1..3).contains(&values.len()) => {
-                let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
-                err.span_note(spans, "consider returning one of these bindings");
-                true
-            }
-            _ => false,
-        }
-    }
-}