diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index e1a2a237c23..7b5c377f7b4 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,263 +1,22 @@
 use crate::infer::type_variable::TypeVariableOriginKind;
-use crate::infer::{InferCtxt, Symbol};
-use rustc_errors::{
-    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
+use crate::infer::InferCtxt;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
+use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
-use rustc_middle::ty::print::Print;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
-use rustc_span::symbol::kw;
-use rustc_span::{sym, Span};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
+use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, InferConst};
+use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::{BytePos, Span};
 use std::borrow::Cow;
-
-struct FindHirNodeVisitor<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    target: GenericArg<'tcx>,
-    target_span: Span,
-    found_node_ty: Option<Ty<'tcx>>,
-    found_local_pattern: Option<&'tcx Pat<'tcx>>,
-    found_arg_pattern: Option<&'tcx Pat<'tcx>>,
-    found_closure: Option<&'tcx Expr<'tcx>>,
-    found_method_call: Option<&'tcx Expr<'tcx>>,
-    found_exact_method_call: Option<&'tcx Expr<'tcx>>,
-    found_for_loop_iter: Option<&'tcx Expr<'tcx>>,
-    found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
-}
-
-impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
-        Self {
-            infcx,
-            target,
-            target_span,
-            found_node_ty: None,
-            found_local_pattern: None,
-            found_arg_pattern: None,
-            found_closure: None,
-            found_method_call: None,
-            found_exact_method_call: None,
-            found_for_loop_iter: None,
-            found_use_diagnostic: None,
-        }
-    }
-
-    fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        self.infcx.in_progress_typeck_results?.borrow().node_type_opt(hir_id)
-    }
-
-    fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
-            ty.walk().any(|inner| {
-                inner == self.target
-                    || match (inner.unpack(), self.target.unpack()) {
-                        (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
-                            use ty::{Infer, TyVar};
-                            match (inner_ty.kind(), target_ty.kind()) {
-                                (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
-                                    .infcx
-                                    .inner
-                                    .borrow_mut()
-                                    .type_variables()
-                                    .sub_unified(a_vid, b_vid),
-                                _ => false,
-                            }
-                        }
-                        _ => false,
-                    }
-            })
-        })
-    }
-
-    /// Determine whether the expression, assumed to be the callee within a `Call`,
-    /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
-    fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
-        self.infcx
-            .trait_def_from_hir_fn(callee.hir_id)
-            .map_or(false, |def_id| self.infcx.is_try_conversion(callee.span, def_id))
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
-    type NestedFilter = nested_filter::OnlyBodies;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.infcx.tcx.hir()
-    }
-
-    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
-        if let (None, Some(ty)) =
-            (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
-        {
-            self.found_local_pattern = Some(&*local.pat);
-            self.found_node_ty = Some(ty);
-        }
-        intravisit::walk_local(self, local);
-    }
-
-    fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
-        for param in body.params {
-            if let (None, Some(ty)) =
-                (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
-            {
-                self.found_arg_pattern = Some(&*param.pat);
-                self.found_node_ty = Some(ty);
-            }
-        }
-        intravisit::walk_body(self, body);
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind
-            && let Some(pat) = arm.pat.for_loop_some()
-            && let Some(ty) = self.node_ty_contains_target(pat.hir_id)
-        {
-            self.found_for_loop_iter = Some(scrutinee);
-            self.found_node_ty = Some(ty);
-            return;
-        }
-        if let ExprKind::MethodCall(segment, exprs, _) = expr.kind
-            && segment.ident.span == self.target_span
-            && Some(self.target) == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
-                typeck_results
-                    .borrow()
-                    .node_type_opt(exprs.first().unwrap().hir_id)
-                    .map(Into::into)
-            })
-        {
-            self.found_exact_method_call = Some(&expr);
-            return;
-        }
-
-        // FIXME(const_generics): Currently, any uninferred `const` generics arguments
-        // are handled specially, but instead they should be handled in `annotate_method_call`,
-        // which currently doesn't work because this evaluates to `false` for const arguments.
-        // See https://github.com/rust-lang/rust/pull/77758 for more details.
-        if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
-            match expr.kind {
-                ExprKind::Closure(..) => self.found_closure = Some(&expr),
-                ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
-
-                // If the given expression falls within the target span and is a
-                // `From::from(e)` call emitted during desugaring of the `?` operator,
-                // extract the types inferred before and after the call
-                ExprKind::Call(callee, [arg])
-                    if self.target_span.contains(expr.span)
-                        && self.found_use_diagnostic.is_none()
-                        && self.is_try_conversion(callee) =>
-                {
-                    self.found_use_diagnostic = self.node_type_opt(arg.hir_id).map(|pre_ty| {
-                        UseDiagnostic::TryConversion { pre_ty, post_ty: ty, span: callee.span }
-                    });
-                }
-                _ => {}
-            }
-        }
-        intravisit::walk_expr(self, expr);
-    }
-}
-
-/// An observation about the use site of a type to be emitted as an additional
-/// note in an inference failure error.
-enum UseDiagnostic<'tcx> {
-    /// Records the types inferred before and after `From::from` is called on the
-    /// error value within the desugaring of the `?` operator.
-    TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span },
-}
-
-impl UseDiagnostic<'_> {
-    /// Return a descriptor of the value at the use site
-    fn descr(&self) -> &'static str {
-        match self {
-            Self::TryConversion { .. } => "error for `?` operator",
-        }
-    }
-
-    /// Return a descriptor of the type at the use site
-    fn type_descr(&self) -> &'static str {
-        match self {
-            Self::TryConversion { .. } => "error type for `?` operator",
-        }
-    }
-
-    fn applies_to(&self, span: Span) -> bool {
-        match *self {
-            // In some cases the span for an inference failure due to try
-            // conversion contains the antecedent expression as well as the `?`
-            Self::TryConversion { span: s, .. } => span.contains(s) && span.hi() == s.hi(),
-        }
-    }
-
-    fn attach_note(&self, err: &mut Diagnostic) {
-        match *self {
-            Self::TryConversion { pre_ty, post_ty, .. } => {
-                let intro = "`?` implicitly converts the error value";
-
-                let msg = match (pre_ty.is_ty_infer(), post_ty.is_ty_infer()) {
-                    (true, true) => format!("{} using the `From` trait", intro),
-                    (false, true) => {
-                        format!("{} into a type implementing `From<{}>`", intro, pre_ty)
-                    }
-                    (true, false) => {
-                        format!("{} into `{}` using the `From` trait", intro, post_ty)
-                    }
-                    (false, false) => {
-                        format!(
-                            "{} into `{}` using its implementation of `From<{}>`",
-                            intro, post_ty, pre_ty
-                        )
-                    }
-                };
-
-                err.note(&msg);
-            }
-        }
-    }
-}
-
-/// Suggest giving an appropriate return type to a closure expression.
-fn closure_return_type_suggestion(
-    err: &mut Diagnostic,
-    output: &FnRetTy<'_>,
-    body: &Body<'_>,
-    ret: &str,
-) {
-    let (arrow, post) = match output {
-        FnRetTy::DefaultReturn(_) => ("-> ", " "),
-        _ => ("", ""),
-    };
-    let suggestion = match body.value.kind {
-        ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
-        _ => vec![
-            (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
-            (body.value.span.shrink_to_hi(), " }".to_string()),
-        ],
-    };
-    err.multipart_suggestion(
-        "give this closure an explicit return type without `_` placeholders",
-        suggestion,
-        Applicability::HasPlaceholders,
-    );
-}
-
-/// Given a closure signature, return a `String` containing a list of all its argument types.
-fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
-    fn_sig
-        .inputs()
-        .skip_binder()
-        .iter()
-        .next()
-        .map(|args| {
-            args.tuple_fields().iter().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", ")
-        })
-        .unwrap_or_default()
-}
+use std::iter;
 
 pub enum TypeAnnotationNeeded {
     /// ```compile_fail,E0282
@@ -296,9 +55,8 @@ pub struct InferenceDiagnosticsData {
 
 /// Data on the parent definition where a generic argument was declared.
 pub struct InferenceDiagnosticsParentData {
-    pub prefix: &'static str,
-    pub name: String,
-    pub def_id: DefId,
+    prefix: &'static str,
+    name: String,
 }
 
 pub enum UnderspecifiedArgKind {
@@ -306,52 +64,58 @@ pub enum UnderspecifiedArgKind {
     Const { is_parameter: bool },
 }
 
-impl UnderspecifiedArgKind {
-    fn descr(&self) -> &'static str {
-        match self {
-            Self::Type { .. } => "type",
-            Self::Const { .. } => "const",
-        }
-    }
-}
-
 impl InferenceDiagnosticsData {
     /// Generate a label for a generic argument which can't be inferred. When not
     /// much is known about the argument, `use_diag` may be used to describe the
     /// labeled value.
-    fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
+    fn cannot_infer_msg(&self) -> String {
         if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
-            if let Some(use_diag) = use_diag {
-                return format!("cannot infer type of {}", use_diag.descr());
-            }
-
             return "cannot infer type".to_string();
         }
 
-        let suffix = match (&self.parent, use_diag) {
-            (Some(parent), _) => format!(" declared on the {} `{}`", parent.prefix, parent.name),
-            (None, Some(use_diag)) => format!(" in {}", use_diag.type_descr()),
-            (None, None) => String::new(),
+        let suffix = match &self.parent {
+            Some(parent) => parent.suffix_string(),
+            None => String::new(),
         };
 
         // For example: "cannot infer type for type parameter `T`"
         format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
     }
+
+    fn where_x_is_specified(&self, in_type: Ty<'_>) -> String {
+        if in_type.is_ty_infer() {
+            String::new()
+        } else if self.name == "_" {
+            // FIXME: Consider specializing this message if there is a single `_`
+            // in the type.
+            ", where the placeholders `_` are specified".to_string()
+        } else {
+            format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name)
+        }
+    }
 }
 
 impl InferenceDiagnosticsParentData {
-    fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
-        let parent_def_id = tcx.parent(def_id);
-
+    fn for_parent_def_id(
+        tcx: TyCtxt<'_>,
+        parent_def_id: DefId,
+    ) -> Option<InferenceDiagnosticsParentData> {
         let parent_name =
             tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
 
         Some(InferenceDiagnosticsParentData {
             prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
             name: parent_name,
-            def_id: parent_def_id,
         })
     }
+
+    fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
+        Self::for_parent_def_id(tcx, tcx.parent(def_id))
+    }
+
+    fn suffix_string(&self) -> String {
+        format!(" declared on the {} `{}`", self.prefix, self.name)
+    }
 }
 
 impl UnderspecifiedArgKind {
@@ -364,6 +128,80 @@ impl UnderspecifiedArgKind {
     }
 }
 
+fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
+    let mut printer = FmtPrinter::new(infcx.tcx, ns);
+    let ty_getter = move |ty_vid| {
+        if infcx.probe_ty_var(ty_vid).is_ok() {
+            warn!("resolved ty var in error message");
+        }
+        if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
+            infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
+        {
+            Some(name.to_string())
+        } else {
+            None
+        }
+    };
+    printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
+    let const_getter = move |ct_vid| {
+        if infcx.probe_const_var(ct_vid).is_ok() {
+            warn!("resolved const var in error message");
+        }
+        if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
+            infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
+        {
+            return Some(name.to_string());
+        } else {
+            None
+        }
+    };
+    printer.const_infer_name_resolver = Some(Box::new(const_getter));
+    printer
+}
+
+fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+    let printer = fmt_printer(infcx, Namespace::TypeNS);
+    let ty = infcx.resolve_vars_if_possible(ty);
+    match ty.kind() {
+        // We don't want the regular output for `fn`s because it includes its path in
+        // invalid pseudo-syntax, we want the `fn`-pointer output instead.
+        ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+        // FIXME: The same thing for closures, but this only works when the closure
+        // does not capture anything.
+        //
+        // We do have to hide the `extern "rust-call"` ABI in that case though,
+        // which is too much of a bother for now.
+        _ => ty.print(printer).unwrap().into_buffer(),
+    }
+}
+
+/// We don't want to directly use `ty_to_string` for closures as their type isn't really
+/// something users are familar with. Directly printing the `fn_sig` of closures also
+/// doesn't work as they actually use the "rust-call" API.
+fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+    let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
+    let fn_sig = substs.as_closure().sig();
+    let args = fn_sig
+        .inputs()
+        .skip_binder()
+        .iter()
+        .next()
+        .map(|args| {
+            args.tuple_fields()
+                .iter()
+                .map(|arg| ty_to_string(infcx, arg))
+                .collect::<Vec<_>>()
+                .join(", ")
+        })
+        .unwrap_or_default();
+    let ret = if fn_sig.output().skip_binder().is_unit() {
+        String::new()
+    } else {
+        format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder()))
+    };
+    format!("fn({}){}", args, ret)
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Extracts data used by diagnostic for either types or constants
     /// which were stuck during inference.
@@ -400,79 +238,55 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 if let Some(highlight) = highlight {
                     printer.region_highlight_mode = highlight;
                 }
-                let name = ty.print(printer).unwrap().into_buffer();
                 InferenceDiagnosticsData {
-                    name,
+                    name: ty.print(printer).unwrap().into_buffer(),
                     span: None,
                     kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
                     parent: None,
                 }
             }
             GenericArgKind::Const(ct) => {
-                match ct.val() {
-                    ty::ConstKind::Infer(InferConst::Var(vid)) => {
-                        let origin = self
-                            .inner
-                            .borrow_mut()
-                            .const_unification_table()
-                            .probe_value(vid)
-                            .origin;
-                        if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
-                            origin.kind
-                        {
-                            return InferenceDiagnosticsData {
-                                name: name.to_string(),
-                                span: Some(origin.span),
-                                kind: UnderspecifiedArgKind::Const { is_parameter: true },
-                                parent: InferenceDiagnosticsParentData::for_def_id(
-                                    self.tcx, def_id,
-                                ),
-                            };
-                        }
-
-                        debug_assert!(!origin.span.is_dummy());
-                        let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
-                        if let Some(highlight) = highlight {
-                            printer.region_highlight_mode = highlight;
-                        }
-                        let name = ct.print(printer).unwrap().into_buffer();
-                        InferenceDiagnosticsData {
-                            name,
+                if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val() {
+                    let origin =
+                        self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+                    if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
+                        origin.kind
+                    {
+                        return InferenceDiagnosticsData {
+                            name: name.to_string(),
                             span: Some(origin.span),
-                            kind: UnderspecifiedArgKind::Const { is_parameter: false },
-                            parent: None,
-                        }
+                            kind: UnderspecifiedArgKind::Const { is_parameter: true },
+                            parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
+                        };
                     }
-                    ty::ConstKind::Unevaluated(ty::Unevaluated { substs, .. }) => {
-                        assert!(substs.has_infer_types_or_consts());
 
-                        // FIXME: We only use the first inference variable we encounter in
-                        // `substs` here, this gives insufficiently informative diagnostics
-                        // in case there are multiple inference variables
-                        for s in substs.iter() {
-                            match s.unpack() {
-                                GenericArgKind::Type(t) => match t.kind() {
-                                    ty::Infer(_) => {
-                                        return self.extract_inference_diagnostics_data(s, None);
-                                    }
-                                    _ => {}
-                                },
-                                GenericArgKind::Const(c) => match c.val() {
-                                    ty::ConstKind::Infer(InferConst::Var(_)) => {
-                                        return self.extract_inference_diagnostics_data(s, None);
-                                    }
-                                    _ => {}
-                                },
-                                _ => {}
-                            }
-                        }
-                        bug!(
-                            "expected an inference variable in substs of unevaluated const {:?}",
-                            ct
-                        );
+                    debug_assert!(!origin.span.is_dummy());
+                    let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+                    if let Some(highlight) = highlight {
+                        printer.region_highlight_mode = highlight;
                     }
-                    _ => {
-                        bug!("unexpect const: {:?}", ct);
+                    InferenceDiagnosticsData {
+                        name: ct.print(printer).unwrap().into_buffer(),
+                        span: Some(origin.span),
+                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                        parent: None,
+                    }
+                } else {
+                    // If we end up here the `FindInferSourceVisitor`
+                    // won't work, as its expected argument isn't an inference variable.
+                    //
+                    // FIXME: Ideally we should look into the generic constant
+                    // to figure out which inference var is actually unresolved so that
+                    // this path is unreachable.
+                    let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+                    if let Some(highlight) = highlight {
+                        printer.region_highlight_mode = highlight;
+                    }
+                    InferenceDiagnosticsData {
+                        name: ct.print(printer).unwrap().into_buffer(),
+                        span: None,
+                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                        parent: None,
                     }
                 }
             }
@@ -480,480 +294,181 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
+    /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
+    /// in case we weren't able to get a better error.
+    fn bad_inference_failure_err(
+        &self,
+        span: Span,
+        arg_data: InferenceDiagnosticsData,
+        error_code: TypeAnnotationNeeded,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let error_code = error_code.into();
+        let mut err = self.tcx.sess.struct_span_err_with_code(
+            span,
+            &format!("type annotations needed"),
+            error_code,
+        );
+        err.span_label(span, arg_data.cannot_infer_msg());
+        err
+    }
+
     pub fn emit_inference_failure_err(
         &self,
         body_id: Option<hir::BodyId>,
         span: Span,
         arg: GenericArg<'tcx>,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        // FIXME(#94483): Either use this or remove it.
+        _impl_candidates: Vec<ty::TraitRef<'tcx>>,
         error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let arg = self.resolve_vars_if_possible(arg);
         let arg_data = self.extract_inference_diagnostics_data(arg, None);
 
-        let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
-        let ty_to_string = |ty: Ty<'tcx>| -> String {
-            let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
-            let ty_getter = move |ty_vid| {
-                if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
-                    self.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
-                {
-                    Some(name.to_string())
-                } else {
-                    None
-                }
-            };
-            printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
-            let const_getter = move |ct_vid| {
-                if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = self
-                    .inner
-                    .borrow_mut()
-                    .const_unification_table()
-                    .probe_value(ct_vid)
-                    .origin
-                    .kind
-                {
-                    return Some(name.to_string());
-                } else {
-                    None
-                }
-            };
-            printer.const_infer_name_resolver = Some(Box::new(const_getter));
-
-            if let ty::FnDef(..) = ty.kind() {
-                // We don't want the regular output for `fn`s because it includes its path in
-                // invalid pseudo-syntax, we want the `fn`-pointer output instead.
-                ty.fn_sig(self.tcx).print(printer).unwrap().into_buffer()
-            } else {
-                ty.print(printer).unwrap().into_buffer()
-            }
+        let Some(typeck_results) = self.in_progress_typeck_results else {
+            // If we don't have any typeck results we're outside
+            // of a body, so we won't be able to get better info
+            // here.
+            return self.bad_inference_failure_err(span, arg_data, error_code);
         };
+        let typeck_results = typeck_results.borrow();
+        let typeck_results = &typeck_results;
 
+        let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
         if let Some(body_id) = body_id {
             let expr = self.tcx.hir().expect_expr(body_id.hir_id);
+            debug!(?expr);
             local_visitor.visit_expr(expr);
         }
-        let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
-            pattern.span
-        } else if let Some(span) = arg_data.span {
-            // `span` here lets us point at `sum` instead of the entire right hand side expr:
-            // error[E0282]: type annotations needed
-            //  --> file2.rs:3:15
-            //   |
-            // 3 |     let _ = x.sum() as f64;
-            //   |               ^^^ cannot infer type for `S`
-            span
-        } else if let Some(ExprKind::MethodCall(segment, ..)) =
-            local_visitor.found_method_call.map(|e| &e.kind)
-        {
-            // Point at the call instead of the whole expression:
-            // error[E0284]: type annotations needed
-            //  --> file.rs:2:5
-            //   |
-            // 2 |     [Ok(2)].into_iter().collect()?;
-            //   |                         ^^^^^^^ cannot infer type
-            //   |
-            //   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
-            if span.contains(segment.ident.span) { segment.ident.span } else { span }
-        } else {
-            span
+
+        let Some(InferSource { span, kind }) = local_visitor.infer_source else {
+            return self.bad_inference_failure_err(span, arg_data, error_code)
         };
 
-        let is_named_and_not_impl_trait =
-            |ty: Ty<'_>| &ty.to_string() != "_" && !ty.is_impl_trait();
-
-        let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
-            (_, Some(_)) => String::new(),
-            (Some(ty), _) if ty.is_closure() => {
-                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
-                let fn_sig = substs.as_closure().sig();
-                let args = closure_args(&fn_sig);
-                let ret = fn_sig.output().skip_binder().to_string();
-                format!(" for the closure `fn({}) -> {}`", args, ret)
-            }
-            (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
-                let ty = ty_to_string(ty);
-                format!(" for `{}`", ty)
-            }
-            _ => String::new(),
-        };
-
-        // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
-        // trying to infer. In the following example, `ty_msg` contains
-        // " for `std::result::Result<i32, E>`":
-        // ```
-        // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
-        //  --> file.rs:L:CC
-        //   |
-        // L |     let b = Ok(4);
-        //   |         -   ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
-        //   |         |
-        //   |         consider giving `b` the explicit type `std::result::Result<i32, E>`, where
-        //   |         the type parameter `E` is specified
-        // ```
         let error_code = error_code.into();
         let mut err = self.tcx.sess.struct_span_err_with_code(
-            err_span,
-            &format!("type annotations needed{}", ty_msg),
+            span,
+            &format!("type annotations needed{}", kind.ty_msg(self)),
             error_code,
         );
-
-        let use_diag = local_visitor.found_use_diagnostic.as_ref();
-        if let Some(use_diag) = use_diag && use_diag.applies_to(err_span) {
-            use_diag.attach_note(&mut err);
-        }
-
-        let param_type = arg_data.kind.descr();
-        let suffix = match local_visitor.found_node_ty {
-            Some(ty) if ty.is_closure() => {
-                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
-                let fn_sig = substs.as_closure().sig();
-                let ret = fn_sig.output().skip_binder().to_string();
-
-                let closure_decl_and_body_id =
-                    local_visitor.found_closure.and_then(|closure| match &closure.kind {
-                        ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
-                        _ => None,
-                    });
-
-                if let Some((decl, body_id)) = closure_decl_and_body_id {
-                    closure_return_type_suggestion(
-                        &mut err,
-                        &decl.output,
-                        self.tcx.hir().body(body_id),
-                        &ret,
-                    );
-                    // We don't want to give the other suggestions when the problem is the
-                    // closure return type.
-                    err.span_label(
-                        span,
-                        arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
-                    );
-                    return err;
-                }
-
-                // This shouldn't be reachable, but just in case we leave a reasonable fallback.
-                let args = closure_args(&fn_sig);
-                // This suggestion is incomplete, as the user will get further type inference
-                // errors due to the `_` placeholders and the introduction of `Box`, but it does
-                // nudge them in the right direction.
-                format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
-            }
-            Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
-                let ty = ty_to_string(ty);
-                format!("the explicit type `{}`, with the {} parameters specified", ty, param_type)
-            }
-            Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
-                let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty);
-                let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty);
-                let ty = ty_to_string(ty);
-                format!(
-                    "the explicit type `{}`, where the {} parameter `{}` is specified",
-                    ty, param_type, arg_data.name,
-                )
-            }
-            _ => "a type".to_string(),
-        };
-
-        if let Some(e) = local_visitor.found_exact_method_call {
-            if let ExprKind::MethodCall(segment, ..) = &e.kind {
-                // Suggest specifying type params or point out the return type of the call:
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/type-annotations-needed-expr.rs:2:39
-                //    |
-                // LL |     let _ = x.into_iter().sum() as f64;
-                //    |                           ^^^
-                //    |                           |
-                //    |                           cannot infer type for `S`
-                //    |                           help: consider specifying the type argument in
-                //    |                           the method call: `sum::<S>`
-                //    |
-                //    = note: type must be known at this point
-                //
-                // or
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/issue-65611.rs:59:20
-                //    |
-                // LL |     let x = buffer.last().unwrap().0.clone();
-                //    |             -------^^^^--
-                //    |             |      |
-                //    |             |      cannot infer type for `T`
-                //    |             this method call resolves to `std::option::Option<&T>`
-                //    |
-                //    = note: type must be known at this point
-                self.annotate_method_call(segment, e, &mut err);
-            }
-        } else if let Some(pattern) = local_visitor.found_arg_pattern {
-            // We don't want to show the default label for closures.
-            //
-            // So, before clearing, the output would look something like this:
-            // ```
-            // let x = |_| {  };
-            //          -  ^^^^ cannot infer type for `[_; 0]`
-            //          |
-            //          consider giving this closure parameter a type
-            // ```
-            //
-            // After clearing, it looks something like this:
-            // ```
-            // let x = |_| {  };
-            //          ^ consider giving this closure parameter the type `[_; 0]`
-            //            with the type parameter `_` specified
-            // ```
-            err.span_label(
-                pattern.span,
-                format!("consider giving this closure parameter {}", suffix),
-            );
-        } else if let Some(pattern) = local_visitor.found_local_pattern {
-            let msg = if let Some(simple_ident) = pattern.simple_ident() {
-                match pattern.span.desugaring_kind() {
-                    None => format!("consider giving `{}` {}", simple_ident, suffix),
-                    Some(_) => format!("this needs {}", suffix),
-                }
-            } else {
-                format!("consider giving this pattern {}", suffix)
-            };
-            err.span_label(pattern.span, msg);
-        } else if let Some(e) = local_visitor.found_method_call {
-            if let ExprKind::MethodCall(segment, exprs, _) = &e.kind {
-                // Suggest impl candidates:
-                //
-                // error[E0283]: type annotations needed
-                //   --> $DIR/E0283.rs:35:24
-                //    |
-                // LL |     let bar = foo_impl.into() * 1u32;
-                //    |               ---------^^^^--
-                //    |               |        |
-                //    |               |        cannot infer type for type parameter `T` declared on the trait `Into`
-                //    |               this method call resolves to `T`
-                //    |               help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
-                //    |
-                //    = note: cannot satisfy `Impl: Into<_>`
-                debug!(?segment);
-                if !impl_candidates.is_empty() && e.span.contains(span)
-                    && let Some(expr) = exprs.first()
-                    && let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
-                    && let [_] = path.segments
-                {
-                    let mut eraser = TypeParamEraser(self.tcx);
-                    let candidate_len = impl_candidates.len();
-                    let mut suggestions: Vec<_> = impl_candidates.iter().filter_map(|candidate| {
-                        let trait_item = self.tcx
-                            .associated_items(candidate.def_id)
-                            .find_by_name_and_kind(
-                                self.tcx,
-                                segment.ident,
-                                ty::AssocKind::Fn,
-                                candidate.def_id
-                            );
-                        if trait_item.is_none() {
-                            return None;
-                        }
-                        let prefix = if let Some(trait_item) = trait_item
-                            && let Some(trait_m) = trait_item.def_id.as_local()
-                            && let hir::TraitItemKind::Fn(fn_, _) = &self.tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }).kind
-                        {
-                            match fn_.decl.implicit_self {
-                                hir::ImplicitSelfKind::ImmRef => "&",
-                                hir::ImplicitSelfKind::MutRef => "&mut ",
-                                _ => "",
-                            }
-                        } else {
-                            ""
-                        };
-                        let candidate = candidate.super_fold_with(&mut eraser);
-                        Some(vec![
-                            (expr.span.shrink_to_lo(), format!("{}::{}({}", candidate, segment.ident, prefix)),
-                            if exprs.len() == 1 {
-                                (expr.span.shrink_to_hi().with_hi(e.span.hi()), ")".to_string())
-                            } else {
-                                (expr.span.shrink_to_hi().with_hi(exprs[1].span.lo()), ", ".to_string())
-                            },
-                        ])
-                    }).collect();
-                    suggestions.sort_by(|a, b| a[0].1.cmp(&b[0].1));
-                    if !suggestions.is_empty() {
-                        err.multipart_suggestions(
-                            &format!(
-                                "use the fully qualified path for the potential candidate{}",
-                                pluralize!(candidate_len),
-                            ),
-                            suggestions.into_iter(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-                // Suggest specifying type params or point out the return type of the call:
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/type-annotations-needed-expr.rs:2:39
-                //    |
-                // LL |     let _ = x.into_iter().sum() as f64;
-                //    |                           ^^^
-                //    |                           |
-                //    |                           cannot infer type for `S`
-                //    |                           help: consider specifying the type argument in
-                //    |                           the method call: `sum::<S>`
-                //    |
-                //    = note: type must be known at this point
-                //
-                // or
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/issue-65611.rs:59:20
-                //    |
-                // LL |     let x = buffer.last().unwrap().0.clone();
-                //    |             -------^^^^--
-                //    |             |      |
-                //    |             |      cannot infer type for `T`
-                //    |             this method call resolves to `std::option::Option<&T>`
-                //    |
-                //    = note: type must be known at this point
-                self.annotate_method_call(segment, e, &mut err);
-            }
-        } else if let Some(scrutinee) = local_visitor.found_for_loop_iter {
-            err.span_label(
-                scrutinee.span,
-                "the element type for this iterator is not specified".to_string(),
-            );
-        }
-        // Instead of the following:
-        // error[E0282]: type annotations needed
-        //  --> file2.rs:3:15
-        //   |
-        // 3 |     let _ = x.sum() as f64;
-        //   |             --^^^--------- cannot infer type for `S`
-        //   |
-        //   = note: type must be known at this point
-        // We want:
-        // error[E0282]: type annotations needed
-        //  --> file2.rs:3:15
-        //   |
-        // 3 |     let _ = x.sum() as f64;
-        //   |               ^^^ cannot infer type for `S`
-        //   |
-        //   = note: type must be known at this point
-        let span = arg_data.span.unwrap_or(err_span);
-
-        // Avoid multiple labels pointing at `span`.
-        if !err
-            .span
-            .span_labels()
-            .iter()
-            .any(|span_label| span_label.label.is_some() && span_label.span == span)
-            && local_visitor.found_arg_pattern.is_none()
-        {
-            // FIXME(const_generics): we would like to handle const arguments
-            // as part of the normal diagnostics flow below, but there appear to
-            // be subtleties in doing so, so for now we special-case const args
-            // here.
-            if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
-                (&arg_data.kind, &arg_data.parent)
-            {
-                // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
-                // as an argument otherwise it will cause the E0282 error.
-                if !self.tcx.generics_of(parent_data.def_id).has_impl_trait()
-                    || self.tcx.features().explicit_generic_args_with_impl_trait
-                {
-                    err.span_suggestion_verbose(
-                        span,
-                        "consider specifying the const argument",
-                        format!("{}::<{}>", parent_data.name, arg_data.name),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-
-            self.report_ambiguous_type_parameter(&mut err, arg);
-            err.span_label(
-                span,
-                arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
-            );
-        }
-
-        err
-    }
-
-    fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
-        // The DefId will be the method's trait item ID unless this is an inherent impl
-        if let Some((DefKind::AssocFn, def_id)) =
-            self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
-        {
-            let parent_def_id = self.tcx.parent(def_id);
-            return self.tcx.is_trait(parent_def_id).then_some(parent_def_id);
-        }
-
-        None
-    }
-
-    /// If the `FnSig` for the method call can be found and type arguments are identified as
-    /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
-    fn annotate_method_call(
-        &self,
-        segment: &hir::PathSegment<'_>,
-        e: &Expr<'_>,
-        err: &mut Diagnostic,
-    ) {
-        if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
-            let borrow = typeck_results.borrow();
-            if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
-                let generics = self.tcx.generics_of(did);
-                if !generics.params.is_empty() && !generics.has_impl_trait() {
-                    err.span_suggestion_verbose(
-                        segment.ident.span.shrink_to_hi(),
-                        &format!(
-                            "consider specifying the type argument{} in the method call",
-                            pluralize!(generics.params.len()),
-                        ),
-                        format!(
-                            "::<{}>",
-                            generics
-                                .params
-                                .iter()
-                                .map(|p| p.name.to_string())
-                                .collect::<Vec<String>>()
-                                .join(", ")
-                        ),
-                        Applicability::HasPlaceholders,
-                    );
+        match kind {
+            InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
+                let suggestion_msg = if let Some(name) = pattern_name {
+                    format!(
+                        "consider giving `{}` an explicit type{}",
+                        name,
+                        arg_data.where_x_is_specified(ty)
+                    )
                 } else {
-                    let sig = self.tcx.fn_sig(did);
-                    let bound_output = sig.output();
-                    let output = bound_output.skip_binder();
-                    err.span_label(e.span, &format!("this method call resolves to `{}`", output));
-                    let kind = output.kind();
-                    if let ty::Projection(proj) = kind {
-                        if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
-                            err.span_label(span, &format!("`{}` defined here", output));
-                        }
-                    }
-                }
+                    format!(
+                        "consider giving this pattern a type{}",
+                        arg_data.where_x_is_specified(ty)
+                    )
+                };
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &suggestion_msg,
+                    format!(": {}", ty_to_string(self, ty)),
+                    Applicability::HasPlaceholders,
+                );
             }
-        }
-    }
+            InferSourceKind::ClosureArg { insert_span, ty } => {
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &format!(
+                        "consider giving this closure parameter an explicit type{}",
+                        arg_data.where_x_is_specified(ty)
+                    ),
+                    format!(": {}", ty_to_string(self, ty)),
+                    Applicability::HasPlaceholders,
+                );
+            }
+            InferSourceKind::GenericArg {
+                insert_span,
+                argument_index,
+                generics_def_id,
+                def_id: _,
+                generic_args,
+            } => {
+                let generics = self.tcx.generics_of(generics_def_id);
+                let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
 
-    fn report_ambiguous_type_parameter(&self, err: &mut Diagnostic, arg: GenericArg<'tcx>) {
-        if let GenericArgKind::Type(ty) = arg.unpack()
-            && let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind()
-        {
-            let mut inner = self.inner.borrow_mut();
-            let ty_vars = &inner.type_variables();
-            let var_origin = ty_vars.var_origin(ty_vid);
-            if let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
-                var_origin.kind
-                && let Some(parent_def_id) = self.tcx.parent(def_id).as_local()
-                && let Some(node) = self.tcx.hir().find_by_def_id(parent_def_id)
-            {
-                match node {
-                    hir::Node::Item(item) if matches!(item.kind, hir::ItemKind::Impl(_) | hir::ItemKind::Fn(..)) => (),
-                    hir::Node::ImplItem(impl_item) if matches!(impl_item.kind, hir::ImplItemKind::Fn(..)) => (),
-                    _ => return,
-                }
-                err.span_help(self.tcx.def_span(def_id), "type parameter declared here");
+                let cannot_infer_msg = format!(
+                    "cannot infer {} of the {} parameter `{}`{}",
+                    if is_type { "type" } else { "the value" },
+                    if is_type { "type" } else { "const" },
+                    generics.params[argument_index].name,
+                    // We use the `generics_def_id` here, as even when suggesting `None::<T>`,
+                    // the type parameter `T` was still declared on the enum, not on the
+                    // variant.
+                    InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
+                        .map_or(String::new(), |parent| parent.suffix_string()),
+                );
+
+                err.span_label(span, cannot_infer_msg);
+
+                let printer = fmt_printer(self, Namespace::TypeNS);
+                let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &format!("consider specifying the generic argument{}", pluralize!(args.len()),),
+                    format!("::<{}>", args),
+                    Applicability::HasPlaceholders,
+                );
+            }
+            InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
+                let printer = fmt_printer(self, Namespace::ValueNS);
+                let def_path = printer.print_def_path(def_id, substs).unwrap().into_buffer();
+
+                // We only care about whether we have to add `&` or `&mut ` for now.
+                // This is the case if the last adjustment is a borrow and the
+                // first adjustment was not a builtin deref.
+                let adjustment = match typeck_results.expr_adjustments(receiver) {
+                    [
+                        Adjustment { kind: Adjust::Deref(None), target: _ },
+                        ..,
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
+                    ] => "",
+                    [
+                        ..,
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
+                    ] => match mut_ {
+                        AutoBorrowMutability::Mut { .. } => "&mut ",
+                        AutoBorrowMutability::Not => "&",
+                    },
+                    _ => "",
+                };
+
+                let suggestion = vec![
+                    (receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")),
+                    (receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
+                ];
+                err.multipart_suggestion_verbose(
+                    "try using a fully qualified path to specify the expected types",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
+            }
+            InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
+                let ret = ty_to_string(self, ty);
+                let (arrow, post) = match data {
+                    FnRetTy::DefaultReturn(_) => ("-> ", " "),
+                    _ => ("", ""),
+                };
+                let suggestion = match should_wrap_expr {
+                    Some(end_span) => vec![
+                        (data.span(), format!("{}{}{}{{ ", arrow, ret, post)),
+                        (end_span, " }".to_string()),
+                    ],
+                    None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))],
+                };
+                err.multipart_suggestion_verbose(
+                    "try giving this closure an explicit return type",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
             }
         }
+        err
     }
 
     pub fn need_type_info_err_in_generator(
@@ -972,136 +487,564 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             "type inside {} must be known in this context",
             kind,
         );
-        err.span_label(span, data.cannot_infer_msg(None));
+        err.span_label(span, data.cannot_infer_msg());
         err
     }
 }
 
-/// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After
-/// performing that replacement, we'll turn all remaining infer type params to use their name from
-/// their definition, and replace all the `[type error]`s back to being infer so they display in
-/// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
-/// by their name *or* `_`, neither of which is desirable: we want to show all types that we could
-/// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
-struct ResolvedTypeParamEraser<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    level: usize,
+#[derive(Debug)]
+struct InferSource<'tcx> {
+    span: Span,
+    kind: InferSourceKind<'tcx>,
 }
 
-impl<'tcx> ResolvedTypeParamEraser<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        ResolvedTypeParamEraser { tcx, level: 0 }
-    }
-
-    /// Replace not yet inferred const params with their def name.
-    fn replace_infers(&self, c: Const<'tcx>, index: u32, name: Symbol) -> Const<'tcx> {
-        match c.val() {
-            ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty()),
-            _ => c,
-        }
-    }
+#[derive(Debug)]
+enum InferSourceKind<'tcx> {
+    LetBinding {
+        insert_span: Span,
+        pattern_name: Option<Ident>,
+        ty: Ty<'tcx>,
+    },
+    ClosureArg {
+        insert_span: Span,
+        ty: Ty<'tcx>,
+    },
+    GenericArg {
+        insert_span: Span,
+        argument_index: usize,
+        generics_def_id: DefId,
+        def_id: DefId,
+        generic_args: &'tcx [GenericArg<'tcx>],
+    },
+    FullyQualifiedMethodCall {
+        receiver: &'tcx Expr<'tcx>,
+        /// If the method has other arguments, this is ", " and the start of the first argument,
+        /// while for methods without arguments this is ")" and the end of the method call.
+        successor: (&'static str, BytePos),
+        substs: SubstsRef<'tcx>,
+        def_id: DefId,
+    },
+    ClosureReturn {
+        ty: Ty<'tcx>,
+        data: &'tcx FnRetTy<'tcx>,
+        should_wrap_expr: Option<Span>,
+    },
 }
 
-impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        self.level += 1;
-        let t = match t.kind() {
-            // We'll hide this type only if all its type params are hidden as well.
-            ty::Adt(def, substs) => {
-                let generics = self.tcx().generics_of(def.did());
-                // Account for params with default values, like `Vec`, where we
-                // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
-                // subst, then we'd get the incorrect output, so we passthrough.
-                let substs: Vec<_> = substs
-                    .iter()
-                    .zip(generics.params.iter())
-                    .map(|(subst, param)| match &(subst.unpack(), &param.kind) {
-                        (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst,
-                        (crate::infer::GenericArgKind::Const(c), _) => {
-                            self.replace_infers(*c, param.index, param.name).into()
-                        }
-                        _ => subst.super_fold_with(self),
-                    })
-                    .collect();
-                let should_keep = |subst: &GenericArg<'_>| match subst.unpack() {
-                    ty::subst::GenericArgKind::Type(t) => match t.kind() {
-                        ty::Error(_) => false,
-                        _ => true,
-                    },
-                    // Account for `const` params here, otherwise `doesnt_infer.rs`
-                    // shows `_` instead of `Foo<{ _: u32 }>`
-                    ty::subst::GenericArgKind::Const(_) => true,
-                    _ => false,
-                };
-                if self.level == 1 || substs.iter().any(should_keep) {
-                    let substs = self.tcx().intern_substs(&substs[..]);
-                    self.tcx().mk_ty(ty::Adt(*def, substs))
+impl<'tcx> InferSourceKind<'tcx> {
+    fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
+        match *self {
+            InferSourceKind::LetBinding { ty, .. }
+            | InferSourceKind::ClosureArg { ty, .. }
+            | InferSourceKind::ClosureReturn { ty, .. } => {
+                if ty.is_closure() {
+                    format!(" for the closure `{}`", closure_as_fn_str(infcx, ty))
+                } else if !ty.is_ty_infer() {
+                    format!(" for `{}`", ty_to_string(infcx, ty))
                 } else {
-                    self.tcx().ty_error()
+                    String::new()
                 }
             }
-            ty::Ref(_, ty, _) => {
-                let ty = self.fold_ty(*ty);
-                match ty.kind() {
-                    // Avoid `&_`, these can be safely presented as `_`.
-                    ty::Error(_) => self.tcx().ty_error(),
-                    _ => t.super_fold_with(self),
+            // FIXME: We should be able to add some additional info here.
+            InferSourceKind::GenericArg { .. }
+            | InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(),
+        }
+    }
+}
+
+struct InsertableGenericArgs<'tcx> {
+    insert_span: Span,
+    substs: SubstsRef<'tcx>,
+    generics_def_id: DefId,
+    def_id: DefId,
+}
+
+/// A visitor which searches for the "best" spot to use in the inference error.
+///
+/// For this it walks over the hir body and tries to check all places where
+/// inference variables could be bound.
+///
+/// While doing so, the currently best spot is stored in `infer_source`.
+/// For details on how we rank spots, see [Self::source_cost]
+struct FindInferSourceVisitor<'a, 'tcx> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    typeck_results: &'a TypeckResults<'tcx>,
+
+    target: GenericArg<'tcx>,
+
+    attempt: usize,
+    infer_source_cost: usize,
+    infer_source: Option<InferSource<'tcx>>,
+}
+
+impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
+    fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        typeck_results: &'a TypeckResults<'tcx>,
+        target: GenericArg<'tcx>,
+    ) -> Self {
+        FindInferSourceVisitor {
+            infcx,
+            typeck_results,
+
+            target,
+
+            attempt: 0,
+            infer_source_cost: usize::MAX,
+            infer_source: None,
+        }
+    }
+
+    /// Computes cost for the given source.
+    ///
+    /// Sources with a small cost are prefer and should result
+    /// in a clearer and idiomatic suggestion.
+    fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
+        let tcx = self.infcx.tcx;
+
+        fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
+            match arg.unpack() {
+                GenericArgKind::Lifetime(_) => 0, // erased
+                GenericArgKind::Type(ty) => ty_cost(ty),
+                GenericArgKind::Const(_) => 3, // some non-zero value
+            }
+        }
+        fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
+            match ty.kind() {
+                ty::Closure(..) => 100,
+                ty::FnDef(..) => 20,
+                ty::FnPtr(..) => 10,
+                ty::Infer(..) => 0,
+                _ => 1,
+            }
+        }
+
+        // The sources are listed in order of preference here.
+        match source.kind {
+            InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
+            InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
+            InferSourceKind::GenericArg { def_id, generic_args, .. } => {
+                let variant_cost = match tcx.def_kind(def_id) {
+                    DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
+                    _ => 12,
+                };
+                variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
+            }
+            InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
+                20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
+            }
+            InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
+                30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
+            }
+        }
+    }
+
+    /// Uses `fn source_cost` to determine whether this inference source is preferable to
+    /// previous sources. We generally prefer earlier sources.
+    #[instrument(level = "debug", skip(self))]
+    fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
+        let cost = self.source_cost(&new_source) + self.attempt;
+        self.attempt += 1;
+        if cost < self.infer_source_cost {
+            self.infer_source_cost = cost;
+            self.infer_source = Some(new_source);
+        }
+    }
+
+    fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+        let ty = self.typeck_results.node_type_opt(hir_id);
+        self.infcx.resolve_vars_if_possible(ty)
+    }
+
+    // Check whether this generic argument is the inference variable we
+    // are looking for.
+    fn generic_arg_is_target(&self, arg: GenericArg<'tcx>) -> bool {
+        if arg == self.target {
+            return true;
+        }
+
+        match (arg.unpack(), self.target.unpack()) {
+            (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+                use ty::{Infer, TyVar};
+                match (inner_ty.kind(), target_ty.kind()) {
+                    (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
+                        self.infcx.inner.borrow_mut().type_variables().sub_unified(a_vid, b_vid)
+                    }
+                    _ => false,
                 }
             }
-            // We could account for `()` if we wanted to replace it, but it's assured to be short.
-            ty::Tuple(_)
-            | ty::Slice(_)
-            | ty::RawPtr(_)
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Opaque(..)
-            | ty::Projection(_)
-            | ty::Never => t.super_fold_with(self),
-            ty::Array(ty, c) => {
-                self.tcx().mk_ty(ty::Array(self.fold_ty(*ty), self.replace_infers(*c, 0, sym::N)))
+            (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => {
+                use ty::InferConst::*;
+                match (inner_ct.val(), target_ct.val()) {
+                    (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self
+                        .infcx
+                        .inner
+                        .borrow_mut()
+                        .const_unification_table()
+                        .unioned(a_vid, b_vid),
+                    _ => false,
+                }
+            }
+            _ => false,
+        }
+    }
+
+    /// Does this generic argument contain our target inference variable
+    /// in a way which can be written by the user.
+    fn generic_arg_contains_target(&self, arg: GenericArg<'tcx>) -> bool {
+        let mut walker = arg.walk();
+        while let Some(inner) = walker.next() {
+            if self.generic_arg_is_target(inner) {
+                return true;
+            }
+            match inner.unpack() {
+                GenericArgKind::Lifetime(_) => {}
+                GenericArgKind::Type(ty) => {
+                    if matches!(ty.kind(), ty::Opaque(..) | ty::Closure(..) | ty::Generator(..)) {
+                        // Opaque types can't be named by the user right now.
+                        //
+                        // Both the generic arguments of closures and generators can
+                        // also not be named. We may want to only look into the closure
+                        // signature in case it has no captures, as that can be represented
+                        // using `fn(T) -> R`.
+
+                        // FIXME(type_alias_impl_trait): These opaque types
+                        // can actually be named, so it would make sense to
+                        // adjust this case and add a test for it.
+                        walker.skip_current_subtree();
+                    }
+                }
+                GenericArgKind::Const(ct) => {
+                    if matches!(ct.val(), ty::ConstKind::Unevaluated(..)) {
+                        // You can't write the generic arguments for
+                        // unevaluated constants.
+                        walker.skip_current_subtree();
+                    }
+                }
+            }
+        }
+        false
+    }
+
+    fn expr_inferred_subst_iter(
+        &self,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+        let tcx = self.infcx.tcx;
+        match expr.kind {
+            hir::ExprKind::Path(ref path) => {
+                if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) {
+                    return self.path_inferred_subst_iter(expr.hir_id, substs, path);
+                }
+            }
+            hir::ExprKind::Struct(path, _, _) => {
+                if let Some(ty) = self.opt_node_type(expr.hir_id) {
+                    if let ty::Adt(_, substs) = ty.kind() {
+                        return self.path_inferred_subst_iter(expr.hir_id, substs, path);
+                    }
+                }
+            }
+            hir::ExprKind::MethodCall(segment, _, _) => {
+                if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
+                    let generics = tcx.generics_of(def_id);
+                    let insertable: Option<_> = try {
+                        if generics.has_impl_trait() {
+                            None?
+                        }
+                        let substs = self.typeck_results.node_substs_opt(expr.hir_id)?;
+                        let span = tcx.hir().span(segment.hir_id?);
+                        let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                        InsertableGenericArgs {
+                            insert_span,
+                            substs,
+                            generics_def_id: def_id,
+                            def_id,
+                        }
+                    };
+                    return Box::new(insertable.into_iter());
+                }
+            }
+            _ => {}
+        }
+
+        Box::new(iter::empty())
+    }
+
+    fn resolved_path_inferred_subst_iter(
+        &self,
+        path: &'tcx hir::Path<'tcx>,
+        substs: SubstsRef<'tcx>,
+    ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
+        let tcx = self.infcx.tcx;
+        // The last segment of a path often has `Res::Err` and the
+        // correct `Res` is the one of the whole path.
+        //
+        // FIXME: We deal with that one separately for now,
+        // would be good to remove this special case.
+        let last_segment_using_path_data: Option<_> = try {
+            let generics_def_id = tcx.res_generics_def_id(path.res)?;
+            let generics = tcx.generics_of(generics_def_id);
+            if generics.has_impl_trait() {
+                None?
+            }
+            let insert_span =
+                path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
+            InsertableGenericArgs {
+                insert_span,
+                substs,
+                generics_def_id,
+                def_id: path.res.def_id(),
             }
-            // We don't want to hide type params that haven't been resolved yet.
-            // This would be the type that will be written out with the type param
-            // name in the output.
-            ty::Infer(_) => t,
-            // We don't want to hide the outermost type, only its type params.
-            _ if self.level == 1 => t.super_fold_with(self),
-            // Hide this type
-            _ => self.tcx().ty_error(),
         };
-        self.level -= 1;
-        t
-    }
-}
 
-/// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
-struct ErrTypeParamEraser<'tcx>(TyCtxt<'tcx>);
-impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.0
+        path.segments
+            .iter()
+            .filter_map(move |segment| {
+                let res = segment.res?;
+                let generics_def_id = tcx.res_generics_def_id(res)?;
+                let generics = tcx.generics_of(generics_def_id);
+                if generics.has_impl_trait() {
+                    return None;
+                }
+                let span = tcx.hir().span(segment.hir_id?);
+                let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                Some(InsertableGenericArgs {
+                    insert_span,
+                    substs,
+                    generics_def_id,
+                    def_id: res.def_id(),
+                })
+            })
+            .chain(last_segment_using_path_data)
     }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match t.kind() {
-            ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
-            _ => t.super_fold_with(self),
+
+    fn path_inferred_subst_iter(
+        &self,
+        hir_id: HirId,
+        substs: SubstsRef<'tcx>,
+        qpath: &'tcx hir::QPath<'tcx>,
+    ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+        let tcx = self.infcx.tcx;
+        match qpath {
+            hir::QPath::Resolved(_self_ty, path) => {
+                Box::new(self.resolved_path_inferred_subst_iter(path, substs))
+            }
+            hir::QPath::TypeRelative(ty, segment) => {
+                let Some(def_id) = self.typeck_results.type_dependent_def_id(hir_id) else {
+                    return Box::new(iter::empty());
+                };
+
+                let generics = tcx.generics_of(def_id);
+                let segment: Option<_> = try {
+                    if !segment.infer_args || generics.has_impl_trait() {
+                        None?;
+                    }
+                    let span = tcx.hir().span(segment.hir_id?);
+                    let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                    InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
+                };
+
+                let parent_def_id = generics.parent.unwrap();
+                if tcx.def_kind(parent_def_id) == DefKind::Impl {
+                    let parent_ty = tcx.bound_type_of(parent_def_id).subst(tcx, substs);
+                    match (parent_ty.kind(), &ty.kind) {
+                        (
+                            ty::Adt(def, substs),
+                            hir::TyKind::Path(hir::QPath::Resolved(_self_ty, path)),
+                        ) => {
+                            if tcx.res_generics_def_id(path.res) != Some(def.did()) {
+                                bug!(
+                                    "unexpected path: def={:?} substs={:?} path={:?}",
+                                    def,
+                                    substs,
+                                    path,
+                                );
+                            } else {
+                                return Box::new(
+                                    self.resolved_path_inferred_subst_iter(path, substs)
+                                        .chain(segment),
+                                );
+                            }
+                        }
+                        _ => (),
+                    }
+                }
+
+                Box::new(segment.into_iter())
+            }
+            hir::QPath::LangItem(_, _, _) => Box::new(iter::empty()),
         }
     }
 }
 
-/// Replace type parameters with `ty::Infer(ty::Var)` to display `_`.
-struct TypeParamEraser<'tcx>(TyCtxt<'tcx>);
+impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
+    type NestedFilter = nested_filter::OnlyBodies;
 
-impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.0
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.infcx.tcx.hir()
     }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match t.kind() {
-            ty::Param(_) | ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
-            _ => t.super_fold_with(self),
+
+    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
+        intravisit::walk_local(self, local);
+
+        if let Some(ty) = self.opt_node_type(local.hir_id) {
+            if self.generic_arg_contains_target(ty.into()) {
+                match local.source {
+                    LocalSource::Normal if local.ty.is_none() => {
+                        self.update_infer_source(InferSource {
+                            span: local.pat.span,
+                            kind: InferSourceKind::LetBinding {
+                                insert_span: local.pat.span.shrink_to_hi(),
+                                pattern_name: local.pat.simple_ident(),
+                                ty,
+                            },
+                        })
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+
+    /// For closures, we first visit the parameters and then the content,
+    /// as we prefer those.
+    fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
+        for param in body.params {
+            debug!(
+                "param: span {:?}, ty_span {:?}, pat.span {:?}",
+                param.span, param.ty_span, param.pat.span
+            );
+            if param.ty_span != param.pat.span {
+                debug!("skipping param: has explicit type");
+                continue;
+            }
+
+            let Some(param_ty) = self.opt_node_type(param.hir_id) else {
+                continue
+            };
+
+            if self.generic_arg_contains_target(param_ty.into()) {
+                self.update_infer_source(InferSource {
+                    span: param.pat.span,
+                    kind: InferSourceKind::ClosureArg {
+                        insert_span: param.pat.span.shrink_to_hi(),
+                        ty: param_ty,
+                    },
+                })
+            }
+        }
+        intravisit::walk_body(self, body);
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let tcx = self.infcx.tcx;
+        match expr.kind {
+            // When encountering `func(arg)` first look into `arg` and then `func`,
+            // as `arg` is "more specific".
+            ExprKind::Call(func, args) => {
+                for arg in args {
+                    self.visit_expr(arg);
+                }
+                self.visit_expr(func);
+            }
+            _ => intravisit::walk_expr(self, expr),
+        }
+
+        for InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } in
+            self.expr_inferred_subst_iter(expr)
+        {
+            let generics = tcx.generics_of(generics_def_id);
+            if let Some(argument_index) =
+                generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg))
+            {
+                let substs = self.infcx.resolve_vars_if_possible(substs);
+                let num_args = generics
+                    .params
+                    .iter()
+                    .rev()
+                    .filter(|&p| !matches!(p.kind, GenericParamDefKind::Lifetime))
+                    .skip_while(|&param| {
+                        if let Some(default) = param.default_value(tcx) {
+                            // FIXME: Using structural comparisions has a bunch of false negatives.
+                            //
+                            // We should instead try to replace inference variables with placeholders and
+                            // then use `infcx.can_eq`. That probably should be a separate method
+                            // generally used during error reporting.
+                            default.subst(tcx, substs) == substs[param.index as usize]
+                        } else {
+                            false
+                        }
+                    })
+                    .count();
+                let generic_args =
+                    &generics.own_substs(substs)[generics.own_counts().lifetimes..][..num_args];
+                let span = match expr.kind {
+                    ExprKind::MethodCall(path, _, _) => path.ident.span,
+                    _ => expr.span,
+                };
+
+                self.update_infer_source(InferSource {
+                    span,
+                    kind: InferSourceKind::GenericArg {
+                        insert_span,
+                        argument_index,
+                        generics_def_id,
+                        def_id,
+                        generic_args,
+                    },
+                });
+            }
+        }
+
+        if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
+            if let (&ExprKind::Closure(_, decl, body_id, span, _), ty::Closure(_, substs)) =
+                (&expr.kind, node_ty.kind())
+            {
+                let output = substs.as_closure().sig().output().skip_binder();
+                if self.generic_arg_contains_target(output.into()) {
+                    let body = self.infcx.tcx.hir().body(body_id);
+                    let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
+                        None
+                    } else {
+                        Some(body.value.span.shrink_to_hi())
+                    };
+                    self.update_infer_source(InferSource {
+                        span,
+                        kind: InferSourceKind::ClosureReturn {
+                            ty: output,
+                            data: &decl.output,
+                            should_wrap_expr,
+                        },
+                    })
+                }
+            }
+        }
+
+        let has_impl_trait = |def_id| {
+            iter::successors(Some(tcx.generics_of(def_id)), |generics| {
+                generics.parent.map(|def_id| tcx.generics_of(def_id))
+            })
+            .any(|generics| generics.has_impl_trait())
+        };
+        if let ExprKind::MethodCall(path, args, span) = expr.kind
+            && let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id)
+            && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
+            && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
+            && self.infcx.tcx.trait_of_item(def_id).is_some()
+            && !has_impl_trait(def_id)
+        {
+            let successor =
+                args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
+            let substs = self.infcx.resolve_vars_if_possible(substs);
+            self.update_infer_source(InferSource {
+                span: path.ident.span,
+                kind: InferSourceKind::FullyQualifiedMethodCall {
+                    receiver: args.first().unwrap(),
+                    successor,
+                    substs,
+                    def_id,
+                }
+            })
         }
     }
 }
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 0f13a9b1388..7769a68ba2a 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -22,6 +22,7 @@
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(try_blocks)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 97f429cfd3f..7a1bdd6beca 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -983,7 +983,11 @@ impl<'hir> Map<'hir> {
             Node::AnonConst(constant) => self.body(constant.body).value.span,
             Node::Expr(expr) => expr.span,
             Node::Stmt(stmt) => stmt.span,
-            Node::PathSegment(seg) => seg.ident.span,
+            Node::PathSegment(seg) => {
+                let ident_span = seg.ident.span;
+                ident_span
+                    .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
+            }
             Node::Ty(ty) => ty.span,
             Node::TraitRef(tr) => tr.path.span,
             Node::Binding(pat) => pat.span,
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index d9b82ee0a76..1feabb2d6b1 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -63,6 +63,29 @@ impl GenericParamDef {
             bug!("cannot convert a non-lifetime parameter def to an early bound region")
         }
     }
+
+    pub fn has_default(&self) -> bool {
+        match self.kind {
+            GenericParamDefKind::Type { has_default, .. }
+            | GenericParamDefKind::Const { has_default } => has_default,
+            GenericParamDefKind::Lifetime => false,
+        }
+    }
+
+    pub fn default_value<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+    ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> {
+        match self.kind {
+            GenericParamDefKind::Type { has_default, .. } if has_default => {
+                Some(EarlyBinder(tcx.type_of(self.def_id).into()))
+            }
+            GenericParamDefKind::Const { has_default } if has_default => {
+                Some(EarlyBinder(tcx.const_param_default(self.def_id).into()))
+            }
+            _ => None,
+        }
+    }
 }
 
 #[derive(Default)]
@@ -204,6 +227,12 @@ impl<'tcx> Generics {
             matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
         })
     }
+
+    /// Returns the substs corresponding to the generic parameters of this item, excluding `Self`.
+    pub fn own_substs(&'tcx self, substs: SubstsRef<'tcx>) -> &'tcx [ty::GenericArg<'tcx>] {
+        let own = &substs[self.parent_count..][..self.params.len()];
+        if self.has_self && self.parent.is_none() { &own[1..] } else { &own }
+    }
 }
 
 /// Bounds on generics.
diff --git a/src/test/ui/array-slice-vec/infer_array_len.stderr b/src/test/ui/array-slice-vec/infer_array_len.stderr
index 6eed4ce4f0c..8da6d97251b 100644
--- a/src/test/ui/array-slice-vec/infer_array_len.stderr
+++ b/src/test/ui/array-slice-vec/infer_array_len.stderr
@@ -2,9 +2,13 @@ error[E0282]: type annotations needed
   --> $DIR/infer_array_len.rs:19:9
    |
 LL |     let [_, _] = a.into();
-   |         ^^^^^^ consider giving this pattern a type
+   |         ^^^^^^
    |
    = note: type must be known at this point
+help: consider giving this pattern a type
+   |
+LL |     let [_, _]: _ = a.into();
+   |               +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/array-slice-vec/vector-no-ann.stderr b/src/test/ui/array-slice-vec/vector-no-ann.stderr
index 8a7b8d22760..d2ea08aa474 100644
--- a/src/test/ui/array-slice-vec/vector-no-ann.stderr
+++ b/src/test/ui/array-slice-vec/vector-no-ann.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/vector-no-ann.rs:2:16
+  --> $DIR/vector-no-ann.rs:2:9
    |
 LL |     let _foo = Vec::new();
-   |         ----   ^^^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `_foo` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |         ^^^^
+   |
+help: consider giving `_foo` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let _foo: Vec<T> = Vec::new();
+   |             ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
index 2005bd4dd5c..db7586bee49 100644
--- a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
+++ b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27
    |
 LL |     with_closure(|x: u32, y| {});
-   |                           ^ consider giving this closure parameter a type
+   |                           ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     with_closure(|x: u32, y: B| {});
+   |                            +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr
index 54825cb746d..38d9d08ce36 100644
--- a/src/test/ui/closures/issue-52437.stderr
+++ b/src/test/ui/closures/issue-52437.stderr
@@ -8,7 +8,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-52437.rs:2:30
    |
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
-   |                              ^ consider giving this closure parameter a type
+   |                              ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize]
+   |                               +++
 
 error[E0308]: mismatched types
   --> $DIR/issue-52437.rs:2:5
diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.stderr b/src/test/ui/const-generics/defaults/doesnt_infer.stderr
index cccf433e328..227b2f40223 100644
--- a/src/test/ui/const-generics/defaults/doesnt_infer.stderr
+++ b/src/test/ui/const-generics/defaults/doesnt_infer.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `Foo<N>`
-  --> $DIR/doesnt_infer.rs:11:15
+  --> $DIR/doesnt_infer.rs:11:9
    |
 LL |     let foo = Foo::foo();
-   |         ---   ^^^^^^^^ cannot infer the value of const parameter `N`
-   |         |
-   |         consider giving `foo` the explicit type `Foo<N>`, where the const parameter `N` is specified
+   |         ^^^
+   |
+help: consider giving `foo` an explicit type, where the the value of const parameter `N` is specified
+   |
+LL |     let foo: Foo<N> = Foo::foo();
+   |            ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr
index 347cd2364b2..463605e2431 100644
--- a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr
+++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr
@@ -1,10 +1,8 @@
 error[E0283]: type annotations needed for `Mask<_, LANES>`
-  --> $DIR/issue-91614.rs:6:13
+  --> $DIR/issue-91614.rs:6:9
    |
 LL |     let y = Mask::<_, _>::splat(false);
-   |         -   ^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `y` the explicit type `Mask<_, LANES>`, where the type parameter `T` is specified
+   |         ^
    |
    = note: cannot satisfy `_: MaskElement`
 note: required by a bound in `Mask::<T, LANES>::splat`
@@ -12,6 +10,10 @@ note: required by a bound in `Mask::<T, LANES>::splat`
    |
 LL |     T: MaskElement,
    |        ^^^^^^^^^^^ required by this bound in `Mask::<T, LANES>::splat`
+help: consider giving `y` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let y: Mask<_, LANES> = Mask::<_, _>::splat(false);
+   |          ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
index e59f1ac8027..9e8328d3701 100644
--- a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
@@ -2,13 +2,18 @@ error[E0282]: type annotations needed
   --> $DIR/const_eval_resolve_canonical.rs:26:9
    |
 LL |     let mut _q = Default::default();
-   |         ^^^^^^ consider giving `_q` a type
+   |         ^^^^^^
+   |
+help: consider giving `_q` an explicit type
+   |
+LL |     let mut _q: _ = Default::default();
+   |               +++
 
 error[E0283]: type annotations needed
   --> $DIR/const_eval_resolve_canonical.rs:29:10
    |
 LL |     _q = foo::<_, 2>(_q);
-   |          ^^^^^^^^^^^ cannot infer type
+   |          ^^^^^^^^^^^ cannot infer the value of the constant `{ N + 1 }`
    |
 note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
   --> $DIR/const_eval_resolve_canonical.rs:8:1
diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.stderr
index 828f4972403..93e45a88a6c 100644
--- a/src/test/ui/const-generics/infer/cannot-infer-const-args.stderr
+++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.stderr
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/cannot-infer-const-args.rs:6:5
    |
 LL |     foo();
-   |     ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
+   |     ^^^ cannot infer the value of the const parameter `X` declared on the function `foo`
    |
-help: consider specifying the const argument
+help: consider specifying the generic argument
    |
 LL |     foo::<X>();
-   |     ~~~~~~~~
+   |        +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/infer/issue-77092.stderr b/src/test/ui/const-generics/infer/issue-77092.stderr
index a625ed2bdc3..1682b26ac87 100644
--- a/src/test/ui/const-generics/infer/issue-77092.stderr
+++ b/src/test/ui/const-generics/infer/issue-77092.stderr
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-77092.rs:11:26
    |
 LL |         println!("{:?}", take_array_from_mut(&mut arr, i));
-   |                          ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut`
+   |                          ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `take_array_from_mut`
    |
-help: consider specifying the const argument
+help: consider specifying the generic arguments
    |
-LL |         println!("{:?}", take_array_from_mut::<N>(&mut arr, i));
-   |                          ~~~~~~~~~~~~~~~~~~~~~~~~
+LL |         println!("{:?}", take_array_from_mut::<i32, N>(&mut arr, i));
+   |                                             ++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/infer/method-chain.stderr b/src/test/ui/const-generics/infer/method-chain.stderr
index 53d92e5ae72..ff6da535bd2 100644
--- a/src/test/ui/const-generics/infer/method-chain.stderr
+++ b/src/test/ui/const-generics/infer/method-chain.stderr
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/method-chain.rs:15:33
    |
 LL |     Foo.bar().bar().bar().bar().baz();
-   |                                 ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
+   |                                 ^^^ cannot infer the value of the const parameter `N` declared on the associated function `baz`
    |
-help: consider specifying the const argument
+help: consider specifying the generic argument
    |
 LL |     Foo.bar().bar().bar().bar().baz::<N>();
-   |                                 ~~~~~~~~
+   |                                    +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/infer/one-param-uninferred.stderr b/src/test/ui/const-generics/infer/one-param-uninferred.stderr
index acf59170c36..98ea8df8252 100644
--- a/src/test/ui/const-generics/infer/one-param-uninferred.stderr
+++ b/src/test/ui/const-generics/infer/one-param-uninferred.stderr
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/one-param-uninferred.rs:9:23
    |
 LL |     let _: [u8; 17] = foo();
-   |                       ^^^ cannot infer the value of const parameter `M` declared on the function `foo`
+   |                       ^^^ cannot infer the value of the const parameter `M` declared on the function `foo`
    |
-help: consider specifying the const argument
+help: consider specifying the generic arguments
    |
-LL |     let _: [u8; 17] = foo::<M>();
-   |                       ~~~~~~~~
+LL |     let _: [u8; 17] = foo::<17_usize, M>();
+   |                          +++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/infer/uninferred-consts.stderr b/src/test/ui/const-generics/infer/uninferred-consts.stderr
index a6c79fc058a..3980ecea863 100644
--- a/src/test/ui/const-generics/infer/uninferred-consts.stderr
+++ b/src/test/ui/const-generics/infer/uninferred-consts.stderr
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/uninferred-consts.rs:9:9
    |
 LL |     Foo.foo();
-   |         ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
+   |         ^^^ cannot infer the value of the const parameter `A` declared on the associated function `foo`
    |
-help: consider specifying the const argument
+help: consider specifying the generic arguments
    |
-LL |     Foo.foo::<A>();
-   |         ~~~~~~~~
+LL |     Foo.foo::<A, B>();
+   |            ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-83249.stderr b/src/test/ui/const-generics/issues/issue-83249.stderr
index 3f44a54e80a..362b8554b2f 100644
--- a/src/test/ui/const-generics/issues/issue-83249.stderr
+++ b/src/test/ui/const-generics/issues/issue-83249.stderr
@@ -1,16 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-83249.rs:19:13
+  --> $DIR/issue-83249.rs:19:9
    |
 LL |     let _ = foo([0; 1]);
-   |         -   ^^^ cannot infer type for type parameter `T` declared on the function `foo`
-   |         |
-   |         consider giving this pattern a type
+   |         ^
    |
-help: type parameter declared here
-  --> $DIR/issue-83249.rs:12:8
+help: consider giving this pattern a type
    |
-LL | fn foo<T: Foo>(_: [u8; T::N]) -> T {
-   |        ^
+LL |     let _: _ = foo([0; 1]);
+   |          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-64662.stderr b/src/test/ui/consts/issue-64662.stderr
index caa582d87f5..21a419711a9 100644
--- a/src/test/ui/consts/issue-64662.stderr
+++ b/src/test/ui/consts/issue-64662.stderr
@@ -2,25 +2,23 @@ error[E0282]: type annotations needed
   --> $DIR/issue-64662.rs:2:9
    |
 LL |     A = foo(),
-   |         ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |         ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/issue-64662.rs:6:14
+help: consider specifying the generic argument
    |
-LL | const fn foo<T>() -> isize {
-   |              ^
+LL |     A = foo::<T>(),
+   |            +++++
 
 error[E0282]: type annotations needed
   --> $DIR/issue-64662.rs:3:9
    |
 LL |     B = foo(),
-   |         ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |         ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/issue-64662.rs:6:14
+help: consider specifying the generic argument
    |
-LL | const fn foo<T>() -> isize {
-   |              ^
+LL |     B = foo::<T>(),
+   |            +++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0282.stderr b/src/test/ui/error-codes/E0282.stderr
index 0f610a5e42f..d01aa3617c7 100644
--- a/src/test/ui/error-codes/E0282.stderr
+++ b/src/test/ui/error-codes/E0282.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/E0282.rs:2:9
    |
 LL |     let x = "hello".chars().rev().collect();
-   |         ^ consider giving `x` a type
+   |         ^
+   |
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _ = "hello".chars().rev().collect();
+   |          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr
index e2bab486064..a107160d11a 100644
--- a/src/test/ui/error-codes/E0283.stderr
+++ b/src/test/ui/error-codes/E0283.stderr
@@ -10,10 +10,7 @@ error[E0283]: type annotations needed
   --> $DIR/E0283.rs:35:24
    |
 LL |     let bar = foo_impl.into() * 1u32;
-   |               ---------^^^^--
-   |               |        |
-   |               |        cannot infer type for type parameter `T` declared on the trait `Into`
-   |               this method call resolves to `T`
+   |                        ^^^^
    |
 note: multiple `impl`s satisfying `Impl: Into<_>` found
   --> $DIR/E0283.rs:17:1
@@ -23,10 +20,10 @@ LL | impl Into<u32> for Impl {
    = note: and another `impl` found in the `core` crate:
            - impl<T, U> Into<U> for T
              where U: From<T>;
-help: use the fully qualified path for the potential candidate
+help: try using a fully qualified path to specify the expected types
    |
-LL |     let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32;
-   |               ++++++++++++++++++++++++++        ~
+LL |     let bar = <Impl as Into<T>>::into(foo_impl) * 1u32;
+   |               ++++++++++++++++++++++++        ~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr
index e58c9d3116a..81715621dd9 100644
--- a/src/test/ui/error-codes/E0401.stderr
+++ b/src/test/ui/error-codes/E0401.stderr
@@ -36,13 +36,12 @@ error[E0282]: type annotations needed
   --> $DIR/E0401.rs:11:5
    |
 LL |     bfnr(x);
-   |     ^^^^ cannot infer type for type parameter `U` declared on the function `bfnr`
+   |     ^^^^ cannot infer type of the type parameter `U` declared on the function `bfnr`
    |
-help: type parameter declared here
-  --> $DIR/E0401.rs:4:13
+help: consider specifying the generic arguments
    |
-LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
-   |             ^
+LL |     bfnr::<U, V, W>(x);
+   |         +++++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/for/for-loop-unconstrained-element-type.stderr b/src/test/ui/for/for-loop-unconstrained-element-type.stderr
index 580b135ac2d..b1b38f6b919 100644
--- a/src/test/ui/for/for-loop-unconstrained-element-type.stderr
+++ b/src/test/ui/for/for-loop-unconstrained-element-type.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/for-loop-unconstrained-element-type.rs:8:9
+  --> $DIR/for-loop-unconstrained-element-type.rs:8:14
    |
 LL |     for i in Vec::new() { }
-   |         ^    ---------- the element type for this iterator is not specified
-   |         |
-   |         cannot infer type
+   |              ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
+   |
+help: consider specifying the generic argument
+   |
+LL |     for i in Vec::<T>::new() { }
+   |                 +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/issue-91762.stderr b/src/test/ui/generic-associated-types/issue-91762.stderr
index a9c465cdd7e..c2785fee387 100644
--- a/src/test/ui/generic-associated-types/issue-91762.stderr
+++ b/src/test/ui/generic-associated-types/issue-91762.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-91762.rs:25:15
    |
 LL |         ret = <Self::Base as Functor>::fmap(arg);
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `fmap`
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `fmap`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         ret = <Self::Base as Functor>::fmap::<T, U>(arg);
+   |                                            ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/cross-return-site-inference.rs b/src/test/ui/impl-trait/cross-return-site-inference.rs
index a7428f9bf12..d881af9ed8f 100644
--- a/src/test/ui/impl-trait/cross-return-site-inference.rs
+++ b/src/test/ui/impl-trait/cross-return-site-inference.rs
@@ -29,17 +29,17 @@ fn baa(b: bool) -> impl std::fmt::Debug {
 }
 
 fn muh() -> Result<(), impl std::fmt::Debug> {
-    Err("whoops")?; //~^ ERROR type annotations needed
-    Ok(())
+    Err("whoops")?;
+    Ok(()) //~ ERROR type annotations needed
 }
 
 fn muh2() -> Result<(), impl std::fmt::Debug> {
-    return Err(From::from("foo")); //~^ ERROR type annotations needed
+    return Err(From::from("foo")); //~ ERROR type annotations needed
     Ok(())
 }
 
 fn muh3() -> Result<(), impl std::fmt::Debug> {
-    Err(From::from("foo")) //~^ ERROR type annotations needed
+    Err(From::from("foo")) //~ ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/cross-return-site-inference.stderr b/src/test/ui/impl-trait/cross-return-site-inference.stderr
index 5209d7a5743..1ff777e6503 100644
--- a/src/test/ui/impl-trait/cross-return-site-inference.stderr
+++ b/src/test/ui/impl-trait/cross-return-site-inference.stderr
@@ -1,20 +1,35 @@
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:31:24
+  --> $DIR/cross-return-site-inference.rs:33:5
    |
-LL | fn muh() -> Result<(), impl std::fmt::Debug> {
-   |                        ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+LL |     Ok(())
+   |     ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     Ok::<(), E>(())
+   |       +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:36:25
+  --> $DIR/cross-return-site-inference.rs:37:12
    |
-LL | fn muh2() -> Result<(), impl std::fmt::Debug> {
-   |                         ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+LL |     return Err(From::from("foo"));
+   |            ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     return Err::<(), E>(From::from("foo"));
+   |               +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:41:25
+  --> $DIR/cross-return-site-inference.rs:42:5
    |
-LL | fn muh3() -> Result<(), impl std::fmt::Debug> {
-   |                         ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+LL |     Err(From::from("foo"))
+   |     ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     Err::<(), E>(From::from("foo"))
+   |        +++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs b/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs
new file mode 100644
index 00000000000..3a47710d508
--- /dev/null
+++ b/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.rs
@@ -0,0 +1,15 @@
+trait Foo<T> {
+    fn foo(self, f: impl FnOnce());
+}
+
+impl<T> Foo<T> for () {
+    fn foo(self, f: impl FnOnce()) {
+        f()
+    }
+}
+
+fn main() {
+    // FIXME: This should ideally use a fully qualified path
+    // without mentioning the generic arguments of `foo`.
+    ().foo(|| ()) //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr b/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr
new file mode 100644
index 00000000000..a1a629bddbd
--- /dev/null
+++ b/src/test/ui/impl-trait/diagnostics/fully-qualified-path-impl-trait.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/fully-qualified-path-impl-trait.rs:14:8
+   |
+LL |     ().foo(|| ())
+   |        ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/impl-trait/fallback_inference.rs b/src/test/ui/impl-trait/fallback_inference.rs
index 001f9ee4877..98f0bd1af28 100644
--- a/src/test/ui/impl-trait/fallback_inference.rs
+++ b/src/test/ui/impl-trait/fallback_inference.rs
@@ -1,7 +1,7 @@
 use std::marker::PhantomData;
 
 fn weird() -> PhantomData<impl Sized> {
-    PhantomData //~^ ERROR type annotations needed
+    PhantomData //~ ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/fallback_inference.stderr b/src/test/ui/impl-trait/fallback_inference.stderr
index b637ca694c2..4ac3c238fe9 100644
--- a/src/test/ui/impl-trait/fallback_inference.stderr
+++ b/src/test/ui/impl-trait/fallback_inference.stderr
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/fallback_inference.rs:3:27
+  --> $DIR/fallback_inference.rs:4:5
    |
-LL | fn weird() -> PhantomData<impl Sized> {
-   |                           ^^^^^^^^^^ cannot infer type
+LL |     PhantomData
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
+   |
+help: consider specifying the generic argument
+   |
+LL |     PhantomData::<T>
+   |                +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs b/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
index 7876add5aa6..970d84120e0 100644
--- a/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
@@ -5,8 +5,8 @@
 #![feature(type_alias_impl_trait)]
 
 fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
-    Thunk::new(|mut cont| { //~ ERROR type annotations needed
-        cont.reify_as();
+    Thunk::new(|mut cont| {
+        cont.reify_as(); //~ ERROR type annotations needed
         cont
     })
 }
@@ -14,8 +14,8 @@ fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
 type Tait = impl FnOnce(Continuation) -> Continuation;
 
 fn reify_as_tait() -> Thunk<Tait> {
-    Thunk::new(|mut cont| { //~ ERROR type annotations needed
-        cont.reify_as();
+    Thunk::new(|mut cont| {
+        cont.reify_as(); //~ ERROR type annotations needed
         cont
     })
 }
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
index dcf1982312f..11ba5aa7867 100644
--- a/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
@@ -1,16 +1,16 @@
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:8:17
+  --> $DIR/hidden-type-is-opaque-2.rs:9:9
    |
-LL |     Thunk::new(|mut cont| {
-   |                 ^^^^^^^^ consider giving this closure parameter a type
+LL |         cont.reify_as();
+   |         ^^^^ cannot infer type
    |
    = note: type must be known at this point
 
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:17:17
+  --> $DIR/hidden-type-is-opaque-2.rs:18:9
    |
-LL |     Thunk::new(|mut cont| {
-   |                 ^^^^^^^^ consider giving this closure parameter a type
+LL |         cont.reify_as();
+   |         ^^^^ cannot infer type
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/impl-trait/issues/issue-84073.stderr b/src/test/ui/impl-trait/issues/issue-84073.stderr
index 36047d23fed..3c39aa6ce5b 100644
--- a/src/test/ui/impl-trait/issues/issue-84073.stderr
+++ b/src/test/ui/impl-trait/issues/issue-84073.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed for `RaceBuilder<T, Never<T>>`
   --> $DIR/issue-84073.rs:32:16
    |
 LL |     Race::new(|race| race.when());
-   |                ^^^^ consider giving this closure parameter the explicit type `RaceBuilder<T, Never<T>>`, where the type parameter `T` is specified
+   |                ^^^^
+   |
+help: consider giving this closure parameter an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     Race::new(|race: RaceBuilder<T, Never<T>>| race.when());
+   |                    ++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/issues/issue-86719.stderr b/src/test/ui/impl-trait/issues/issue-86719.stderr
index e2abf71c110..09047cdcbe1 100644
--- a/src/test/ui/impl-trait/issues/issue-86719.stderr
+++ b/src/test/ui/impl-trait/issues/issue-86719.stderr
@@ -16,7 +16,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-86719.rs:9:10
    |
 LL |         |_| true
-   |          ^ consider giving this closure parameter a type
+   |          ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |         |_: _| true
+   |           +++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/impl-trait/issues/issue-92305.stderr b/src/test/ui/impl-trait/issues/issue-92305.stderr
index c4fc49225e9..e8575b76b09 100644
--- a/src/test/ui/impl-trait/issues/issue-92305.stderr
+++ b/src/test/ui/impl-trait/issues/issue-92305.stderr
@@ -18,7 +18,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-92305.rs:7:5
    |
 LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the function `empty`
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
 
 error[E0282]: type annotations needed
   --> $DIR/issue-92305.rs:10:35
diff --git a/src/test/ui/inference/ambiguous_type_parameter.stderr b/src/test/ui/inference/ambiguous_type_parameter.stderr
index 47ef1948aee..a08342371b3 100644
--- a/src/test/ui/inference/ambiguous_type_parameter.stderr
+++ b/src/test/ui/inference/ambiguous_type_parameter.stderr
@@ -3,12 +3,6 @@ error[E0282]: type annotations needed
    |
 LL |     InMemoryStore.get_raw(&String::default());
    |                   ^^^^^^^ cannot infer type for type parameter `K`
-   |
-help: type parameter declared here
-  --> $DIR/ambiguous_type_parameter.rs:9:6
-   |
-LL | impl<K> Store<String, HashMap<K, String>> for InMemoryStore {
-   |      ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-async.stderr b/src/test/ui/inference/cannot-infer-async.stderr
index 23360483361..0579cf238a9 100644
--- a/src/test/ui/inference/cannot-infer-async.stderr
+++ b/src/test/ui/inference/cannot-infer-async.stderr
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed
   --> $DIR/cannot-infer-async.rs:13:9
    |
-LL |     let fut = async {
-   |         --- consider giving `fut` a type
-...
 LL |         Ok(())
-   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
+   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         Ok::<(), E>(())
+   |           +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure-circular.rs b/src/test/ui/inference/cannot-infer-closure-circular.rs
index a3b957179b1..ae879db68ec 100644
--- a/src/test/ui/inference/cannot-infer-closure-circular.rs
+++ b/src/test/ui/inference/cannot-infer-closure-circular.rs
@@ -5,10 +5,9 @@ fn main() {
     // note about the `?` operator in the closure body, which isn't relevant to
     // the inference.
     let x = |r| {
-        //~^ ERROR type annotations needed
         let v = r?;
         Ok(v)
     };
 
-    let _ = x(x(Ok(())));
+    let _ = x(x(Ok(())));  //~ ERROR type annotations needed for `Result<(), E>`
 }
diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr
index a6ddb7ae908..3ad8e3cda16 100644
--- a/src/test/ui/inference/cannot-infer-closure-circular.stderr
+++ b/src/test/ui/inference/cannot-infer-closure-circular.stderr
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed for `Result<(), E>`
-  --> $DIR/cannot-infer-closure-circular.rs:7:14
+  --> $DIR/cannot-infer-closure-circular.rs:12:9
    |
-LL |     let x = |r| {
-   |              ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified
+LL |     let _ = x(x(Ok(())));
+   |         ^
+   |
+help: consider giving this pattern a type, where the type for type parameter `E` is specified
+   |
+LL |     let _: Result<(), E> = x(x(Ok(())));
+   |          +++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure.rs b/src/test/ui/inference/cannot-infer-closure.rs
index 6e84b6d5ad0..1c350b18f5a 100644
--- a/src/test/ui/inference/cannot-infer-closure.rs
+++ b/src/test/ui/inference/cannot-infer-closure.rs
@@ -1,6 +1,6 @@
 fn main() {
     let x = |a: (), b: ()| {
         Err(a)?;
-        Ok(b) //~ ERROR type annotations needed for the closure
+        Ok(b) //~ ERROR type annotations needed
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-closure.stderr b/src/test/ui/inference/cannot-infer-closure.stderr
index f8026fafeb2..a4b818e6e2b 100644
--- a/src/test/ui/inference/cannot-infer-closure.stderr
+++ b/src/test/ui/inference/cannot-infer-closure.stderr
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>`
+error[E0282]: type annotations needed
   --> $DIR/cannot-infer-closure.rs:4:9
    |
 LL |         Ok(b)
-   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
+   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
    |
-help: give this closure an explicit return type without `_` placeholders
+help: consider specifying the generic arguments
    |
-LL |     let x = |a: (), b: ()| -> Result<(), _> {
-   |                            ++++++++++++++++
+LL |         Ok::<(), E>(b)
+   |           +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.rs b/src/test/ui/inference/cannot-infer-partial-try-return.rs
index 6e897a3edfd..976827a4478 100644
--- a/src/test/ui/inference/cannot-infer-partial-try-return.rs
+++ b/src/test/ui/inference/cannot-infer-partial-try-return.rs
@@ -16,7 +16,8 @@ fn infallible() -> Result<(), std::convert::Infallible> {
 
 fn main() {
     let x = || -> Result<_, QualifiedError<_>> {
-        infallible()?; //~ ERROR type annotations needed
+        //~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>`
+        infallible()?;
         Ok(())
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
index 3542eb6848c..220602c124c 100644
--- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr
+++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
@@ -1,10 +1,10 @@
-error[E0282]: type annotations needed for the closure `fn() -> Result<(), QualifiedError<_>>`
-  --> $DIR/cannot-infer-partial-try-return.rs:19:9
+error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>`
+  --> $DIR/cannot-infer-partial-try-return.rs:18:13
    |
-LL |         infallible()?;
-   |         ^^^^^^^^^^^^^ cannot infer type
+LL |     let x = || -> Result<_, QualifiedError<_>> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
 LL |     let x = || -> Result<(), QualifiedError<_>> {
    |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/test/ui/inference/erase-type-params-in-label.stderr b/src/test/ui/inference/erase-type-params-in-label.stderr
index 51fac5f79df..fd58844c238 100644
--- a/src/test/ui/inference/erase-type-params-in-label.stderr
+++ b/src/test/ui/inference/erase-type-params-in-label.stderr
@@ -1,46 +1,40 @@
 error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>`
-  --> $DIR/erase-type-params-in-label.rs:2:15
+  --> $DIR/erase-type-params-in-label.rs:2:9
    |
 LL |     let foo = foo(1, "");
-   |         ---   ^^^ cannot infer type for type parameter `W` declared on the function `foo`
-   |         |
-   |         consider giving `foo` the explicit type `Foo<_, _, W, Z>`, where the type parameter `W` is specified
+   |         ^^^
    |
-help: type parameter declared here
-  --> $DIR/erase-type-params-in-label.rs:25:14
-   |
-LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
-   |              ^
    = note: cannot satisfy `_: Default`
 note: required by a bound in `foo`
   --> $DIR/erase-type-params-in-label.rs:25:17
    |
 LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
    |                 ^^^^^^^ required by this bound in `foo`
+help: consider giving `foo` an explicit type, where the type for type parameter `W` is specified
+   |
+LL |     let foo: Foo<i32, &str, W, Z> = foo(1, "");
+   |            ++++++++++++++++++++++
 help: consider specifying the type arguments in the function call
    |
 LL |     let foo = foo::<T, K, W, Z>(1, "");
    |                  ++++++++++++++
 
 error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
-  --> $DIR/erase-type-params-in-label.rs:5:15
+  --> $DIR/erase-type-params-in-label.rs:5:9
    |
 LL |     let bar = bar(1, "");
-   |         ---   ^^^ cannot infer type for type parameter `Z` declared on the function `bar`
-   |         |
-   |         consider giving `bar` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified
+   |         ^^^
    |
-help: type parameter declared here
-  --> $DIR/erase-type-params-in-label.rs:14:14
-   |
-LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
-   |              ^
    = note: cannot satisfy `_: Default`
 note: required by a bound in `bar`
   --> $DIR/erase-type-params-in-label.rs:14:17
    |
 LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
    |                 ^^^^^^^ required by this bound in `bar`
+help: consider giving `bar` an explicit type, where the type for type parameter `Z` is specified
+   |
+LL |     let bar: Bar<i32, &str, Z> = bar(1, "");
+   |            +++++++++++++++++++
 help: consider specifying the type arguments in the function call
    |
 LL |     let bar = bar::<T, K, Z>(1, "");
diff --git a/src/test/ui/inference/issue-71732.stderr b/src/test/ui/inference/issue-71732.stderr
index 0369196c910..db153d38aaa 100644
--- a/src/test/ui/inference/issue-71732.stderr
+++ b/src/test/ui/inference/issue-71732.stderr
@@ -2,9 +2,7 @@ error[E0283]: type annotations needed
   --> $DIR/issue-71732.rs:18:10
    |
 LL |         .get(&"key".into())
-   |          ^^^  ------------ this method call resolves to `T`
-   |          |
-   |          cannot infer type for type parameter `Q` declared on the associated function `get`
+   |          ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
    |
    = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
            - impl Borrow<str> for String;
@@ -15,6 +13,10 @@ note: required by a bound in `HashMap::<K, V, S>::get`
    |
 LL |         K: Borrow<Q>,
    |            ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
+help: consider specifying the generic argument
+   |
+LL |         .get::<Q>(&"key".into())
+   |             +++++
 help: consider specifying the type argument in the function call
    |
 LL |         .get::<Q>(&"key".into())
diff --git a/src/test/ui/inference/issue-72616.stderr b/src/test/ui/inference/issue-72616.stderr
index 0077c734748..3c53d8126e7 100644
--- a/src/test/ui/inference/issue-72616.stderr
+++ b/src/test/ui/inference/issue-72616.stderr
@@ -1,16 +1,18 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-72616.rs:20:30
+  --> $DIR/issue-72616.rs:20:37
    |
 LL |         if String::from("a") == "a".try_into().unwrap() {}
-   |                              ^^ -------------- this method call resolves to `Result<T, <Self as TryInto<T>>::Error>`
-   |                              |
-   |                              cannot infer type
+   |                                     ^^^^^^^^
    |
    = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
            - impl PartialEq for String;
            - impl<'a, 'b> PartialEq<&'a str> for String;
            - impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
            - impl<'a, 'b> PartialEq<str> for String;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
+   |                                 +++++++++++++++++++++++++++++++   ~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/issue-83606.stderr b/src/test/ui/inference/issue-83606.stderr
index 9ca8f35fd54..4ffaf820b82 100644
--- a/src/test/ui/inference/issue-83606.stderr
+++ b/src/test/ui/inference/issue-83606.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `[usize; _]`
-  --> $DIR/issue-83606.rs:8:13
+  --> $DIR/issue-83606.rs:8:9
    |
 LL |     let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
-   |         -   ^^^ cannot infer the value of const parameter `N` declared on the function `foo`
-   |         |
-   |         consider giving this pattern the explicit type `[_; N]`, where the const parameter `N` is specified
+   |         ^
+   |
+help: consider giving this pattern a type, where the the value of const parameter `N` is specified
+   |
+LL |     let _: [usize; _] = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
+   |          ++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/issue-86162-1.stderr b/src/test/ui/inference/issue-86162-1.stderr
index edf97c0aed4..6641b29b30b 100644
--- a/src/test/ui/inference/issue-86162-1.stderr
+++ b/src/test/ui/inference/issue-86162-1.stderr
@@ -1,20 +1,19 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-86162-1.rs:7:5
+  --> $DIR/issue-86162-1.rs:7:9
    |
 LL |     foo(gen()); //<- Do not suggest `foo::<impl Clone>()`!
-   |     ^^^ cannot infer type for type parameter `impl Clone` declared on the function `foo`
+   |         ^^^ cannot infer type of the type parameter `T` declared on the function `gen`
    |
-help: type parameter declared here
-  --> $DIR/issue-86162-1.rs:3:11
-   |
-LL | fn foo(x: impl Clone) {}
-   |           ^^^^^^^^^^
    = note: cannot satisfy `_: Clone`
 note: required by a bound in `foo`
   --> $DIR/issue-86162-1.rs:3:16
    |
 LL | fn foo(x: impl Clone) {}
    |                ^^^^^ required by this bound in `foo`
+help: consider specifying the generic argument
+   |
+LL |     foo(gen::<T>()); //<- Do not suggest `foo::<impl Clone>()`!
+   |            +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/issue-86162-2.stderr b/src/test/ui/inference/issue-86162-2.stderr
index c642ebb0576..d2a026a9269 100644
--- a/src/test/ui/inference/issue-86162-2.stderr
+++ b/src/test/ui/inference/issue-86162-2.stderr
@@ -1,20 +1,19 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-86162-2.rs:12:5
+  --> $DIR/issue-86162-2.rs:12:14
    |
 LL |     Foo::bar(gen()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
-   |     ^^^^^^^^ cannot infer type for type parameter `impl Clone` declared on the associated function `bar`
+   |              ^^^ cannot infer type of the type parameter `T` declared on the function `gen`
    |
-help: type parameter declared here
-  --> $DIR/issue-86162-2.rs:8:15
-   |
-LL |     fn bar(x: impl Clone) {}
-   |               ^^^^^^^^^^
    = note: cannot satisfy `_: Clone`
 note: required by a bound in `Foo::bar`
   --> $DIR/issue-86162-2.rs:8:20
    |
 LL |     fn bar(x: impl Clone) {}
    |                    ^^^^^ required by this bound in `Foo::bar`
+help: consider specifying the generic argument
+   |
+LL |     Foo::bar(gen::<T>()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
+   |                 +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-12187-1.stderr b/src/test/ui/issues/issue-12187-1.stderr
index 3ea15439df2..806b7f0ac05 100644
--- a/src/test/ui/issues/issue-12187-1.stderr
+++ b/src/test/ui/issues/issue-12187-1.stderr
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed for `&T`
-  --> $DIR/issue-12187-1.rs:6:10
+  --> $DIR/issue-12187-1.rs:6:9
    |
 LL |     let &v = new();
-   |         -^
-   |         ||
-   |         |cannot infer type
-   |         consider giving this pattern the explicit type `&T`, with the type parameters specified
+   |         ^^
+   |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+   |
+LL |     let &v: &T = new();
+   |           ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-12187-2.stderr b/src/test/ui/issues/issue-12187-2.stderr
index a5e65c65beb..a1fa0a2b002 100644
--- a/src/test/ui/issues/issue-12187-2.stderr
+++ b/src/test/ui/issues/issue-12187-2.stderr
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed for `&T`
-  --> $DIR/issue-12187-2.rs:6:10
+  --> $DIR/issue-12187-2.rs:6:9
    |
 LL |     let &v = new();
-   |         -^
-   |         ||
-   |         |cannot infer type
-   |         consider giving this pattern the explicit type `&T`, with the type parameters specified
+   |         ^^
+   |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+   |
+LL |     let &v: &T = new();
+   |           ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-16966.stderr b/src/test/ui/issues/issue-16966.stderr
index 09e20c0c777..6eb56ca5516 100644
--- a/src/test/ui/issues/issue-16966.stderr
+++ b/src/test/ui/issues/issue-16966.stderr
@@ -2,9 +2,14 @@ error[E0282]: type annotations needed
   --> $DIR/issue-16966.rs:2:5
    |
 LL |     panic!(std::default::Default::default());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `M` declared on the function `begin_panic`
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider specifying the generic argument
+  --> $SRC_DIR/std/src/panic.rs:LL:COL
+   |
+LL |         $crate::rt::begin_panic::<M>($msg)
+   |                                +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr
index 48405a292f3..5f45a2f8443 100644
--- a/src/test/ui/issues/issue-17551.stderr
+++ b/src/test/ui/issues/issue-17551.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `B<T>`
-  --> $DIR/issue-17551.rs:6:15
+  --> $DIR/issue-17551.rs:6:9
    |
 LL |     let foo = B(marker::PhantomData);
-   |         ---   ^ cannot infer type for type parameter `T` declared on the struct `B`
-   |         |
-   |         consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
+   |         ^^^
+   |
+help: consider giving `foo` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let foo: B<T> = B(marker::PhantomData);
+   |            ++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-18159.stderr b/src/test/ui/issues/issue-18159.stderr
index 9b890be3c78..605ff3829d1 100644
--- a/src/test/ui/issues/issue-18159.stderr
+++ b/src/test/ui/issues/issue-18159.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-18159.rs:2:9
    |
 LL |     let x;
-   |         ^ consider giving `x` a type
+   |         ^
+   |
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _;
+   |          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20261.stderr b/src/test/ui/issues/issue-20261.stderr
index 6330364c92b..73468c7ca16 100644
--- a/src/test/ui/issues/issue-20261.stderr
+++ b/src/test/ui/issues/issue-20261.stderr
@@ -1,8 +1,6 @@
-error[E0282]: type annotations needed for `(_,)`
+error[E0282]: type annotations needed
   --> $DIR/issue-20261.rs:4:11
    |
-LL |     for (ref i,) in [].iter() {
-   |                     --------- this method call resolves to `std::slice::Iter<'_, T>`
 LL |         i.clone();
    |           ^^^^^ cannot infer type
    |
diff --git a/src/test/ui/issues/issue-2151.rs b/src/test/ui/issues/issue-2151.rs
index 32fba4cb217..82cf49de822 100644
--- a/src/test/ui/issues/issue-2151.rs
+++ b/src/test/ui/issues/issue-2151.rs
@@ -1,4 +1,4 @@
 fn main() {
-    let x = panic!();
-    x.clone(); //~ ERROR type annotations needed
+    let x = panic!(); //~ ERROR type annotations needed
+    x.clone();
 }
diff --git a/src/test/ui/issues/issue-2151.stderr b/src/test/ui/issues/issue-2151.stderr
index a2bcc8a8cea..e0d946205ad 100644
--- a/src/test/ui/issues/issue-2151.stderr
+++ b/src/test/ui/issues/issue-2151.stderr
@@ -1,12 +1,14 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-2151.rs:3:5
+  --> $DIR/issue-2151.rs:2:9
    |
 LL |     let x = panic!();
-   |         - consider giving `x` a type
-LL |     x.clone();
-   |     ^ cannot infer type
+   |         ^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _ = panic!();
+   |          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr
index 12b2eb48e7e..1403ecbd92d 100644
--- a/src/test/ui/issues/issue-23046.stderr
+++ b/src/test/ui/issues/issue-23046.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed for `Expr<'_, VAR>`
   --> $DIR/issue-23046.rs:17:15
    |
 LL |     let ex = |x| {
-   |               ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
+   |               ^
+   |
+help: consider giving this closure parameter an explicit type, where the type for type parameter `VAR` is specified
+   |
+LL |     let ex = |x: Expr<'_, VAR>| {
+   |                +++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr
index e6b8367f74f..4622501f33e 100644
--- a/src/test/ui/issues/issue-24036.stderr
+++ b/src/test/ui/issues/issue-24036.stderr
@@ -15,7 +15,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-24036.rs:9:15
    |
 LL |         1 => |c| c + 1,
-   |               ^ consider giving this closure parameter a type
+   |               ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |         1 => |c: _| c + 1,
+   |                +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-25368.rs b/src/test/ui/issues/issue-25368.rs
index 8b4dbb6e460..b7f0f613e80 100644
--- a/src/test/ui/issues/issue-25368.rs
+++ b/src/test/ui/issues/issue-25368.rs
@@ -5,9 +5,10 @@ use std::marker::PhantomData;
 struct Foo<T> {foo: PhantomData<T>}
 
 fn main() {
-    let (tx, rx) = channel();
-
+    let (tx, rx) = //~ ERROR type annotations needed
+        channel();
+    // FIXME(#89862): Suggest adding a generic argument to `channel` instead
     spawn(move || {
-        tx.send(Foo{ foo: PhantomData }); //~ ERROR E0282
+        tx.send(Foo{ foo: PhantomData });
     });
 }
diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr
index 6a970bc0494..ffcb7384952 100644
--- a/src/test/ui/issues/issue-25368.stderr
+++ b/src/test/ui/issues/issue-25368.stderr
@@ -1,11 +1,13 @@
 error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
-  --> $DIR/issue-25368.rs:11:17
+  --> $DIR/issue-25368.rs:8:9
    |
-LL |     let (tx, rx) = channel();
-   |         -------- consider giving this pattern the explicit type `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
-...
-LL |         tx.send(Foo{ foo: PhantomData });
-   |                 ^^^ cannot infer type for type parameter `T` declared on the struct `Foo`
+LL |     let (tx, rx) =
+   |         ^^^^^^^^
+   |
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) =
+   |                 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-47486.stderr b/src/test/ui/issues/issue-47486.stderr
index a029948ca3b..ca57b2d7e01 100644
--- a/src/test/ui/issues/issue-47486.stderr
+++ b/src/test/ui/issues/issue-47486.stderr
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-47486.rs:3:31
+  --> $DIR/issue-47486.rs:3:11
    |
 LL |     [0u8; std::mem::size_of::<_>()];
-   |                               ^ cannot infer type
+   |           ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `size_of`
+   |
+help: consider specifying the generic argument
+   |
+LL |     [0u8; std::mem::size_of::<_>()];
+   |                            ~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-47486.rs:2:10
diff --git a/src/test/ui/issues/issue-5062.stderr b/src/test/ui/issues/issue-5062.stderr
index 9fa15dc9679..3191bd3de32 100644
--- a/src/test/ui/issues/issue-5062.stderr
+++ b/src/test/ui/issues/issue-5062.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-5062.rs:1:29
    |
 LL | fn main() { format!("{:?}", None); }
-   |                             ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |                             ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL | fn main() { format!("{:?}", None::<T>); }
+   |                                 +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51116.rs b/src/test/ui/issues/issue-51116.rs
index c0a74a679ef..c979c7b2cdd 100644
--- a/src/test/ui/issues/issue-51116.rs
+++ b/src/test/ui/issues/issue-51116.rs
@@ -2,7 +2,6 @@ fn main() {
     let tiles = Default::default();
     for row in &mut tiles {
         for tile in row {
-            //~^ NOTE the element type for this iterator is not specified
             *tile = 0;
             //~^ ERROR type annotations needed
             //~| NOTE cannot infer type
diff --git a/src/test/ui/issues/issue-51116.stderr b/src/test/ui/issues/issue-51116.stderr
index 8501ae6a1d0..399b421ab16 100644
--- a/src/test/ui/issues/issue-51116.stderr
+++ b/src/test/ui/issues/issue-51116.stderr
@@ -1,9 +1,6 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-51116.rs:6:13
+  --> $DIR/issue-51116.rs:5:13
    |
-LL |         for tile in row {
-   |                     --- the element type for this iterator is not specified
-LL |
 LL |             *tile = 0;
    |             ^^^^^ cannot infer type
    |
diff --git a/src/test/ui/issues/issue-6458-2.stderr b/src/test/ui/issues/issue-6458-2.stderr
index da16f95dc3d..8dbdd9a2735 100644
--- a/src/test/ui/issues/issue-6458-2.stderr
+++ b/src/test/ui/issues/issue-6458-2.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458-2.rs:3:21
    |
 LL |     format!("{:?}", None);
-   |                     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |                     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL |     format!("{:?}", None::<T>);
+   |                         +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-6458-3.stderr b/src/test/ui/issues/issue-6458-3.stderr
index a71c159db0b..2c3ec1a331f 100644
--- a/src/test/ui/issues/issue-6458-3.stderr
+++ b/src/test/ui/issues/issue-6458-3.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458-3.rs:4:5
    |
 LL |     mem::transmute(0);
-   |     ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute`
+   |     ^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `transmute`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     mem::transmute::<i32, U>(0);
+   |                   ++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-6458.stderr b/src/test/ui/issues/issue-6458.stderr
index f548692d785..2e93c13855f 100644
--- a/src/test/ui/issues/issue-6458.stderr
+++ b/src/test/ui/issues/issue-6458.stderr
@@ -1,14 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-6458.rs:9:4
+  --> $DIR/issue-6458.rs:9:22
    |
 LL |    foo(TypeWithState(marker::PhantomData));
-   |    ^^^ cannot infer type for type parameter `State` declared on the function `foo`
+   |                      ^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
    |
-help: type parameter declared here
-  --> $DIR/issue-6458.rs:6:12
+help: consider specifying the generic argument
    |
-LL | pub fn foo<State>(_: TypeWithState<State>) {}
-   |            ^^^^^
+LL |    foo(TypeWithState(marker::PhantomData::<T>));
+   |                                         +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-66706.stderr b/src/test/ui/issues/issue-66706.stderr
index e8cb18f5c1e..1c55560cb7c 100644
--- a/src/test/ui/issues/issue-66706.stderr
+++ b/src/test/ui/issues/issue-66706.stderr
@@ -30,7 +30,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-66706.rs:2:11
    |
 LL |     [0; [|_: _ &_| ()].len()]
-   |           ^ consider giving this closure parameter a type
+   |           ^ cannot infer type
 
 error[E0308]: mismatched types
   --> $DIR/issue-66706.rs:2:5
diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr
index 378fdc97dd3..6c4eafbc8b3 100644
--- a/src/test/ui/issues/issue-69455.stderr
+++ b/src/test/ui/issues/issue-69455.stderr
@@ -1,22 +1,20 @@
 error[E0282]: type annotations needed
   --> $DIR/issue-69455.rs:29:20
    |
-LL |     type Output;
-   |     ------------ `<Self as Test<Rhs>>::Output` defined here
-...
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    this method call resolves to `<Self as Test<Rhs>>::Output`
-   |                    cannot infer type for type parameter `T` declared on the associated function `new_display`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `new_display`
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider specifying the generic argument
+   |
+LL |     println!("{}", 23u64.test(xs.iter().sum())::<T>);
+   |                                               +++++
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-69455.rs:29:26
+  --> $DIR/issue-69455.rs:29:41
    |
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
-   |                          ^^^^ cannot infer type for type parameter `Rhs` declared on the trait `Test`
+   |                                         ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
 note: multiple `impl`s satisfying `u64: Test<_>` found
   --> $DIR/issue-69455.rs:11:1
@@ -26,7 +24,7 @@ LL | impl Test<u32> for u64 {
 ...
 LL | impl Test<u64> for u64 {
    | ^^^^^^^^^^^^^^^^^^^^^^
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
    |
 LL |     println!("{}", 23u64.test(xs.iter().sum::<S>()));
    |                                            +++++
diff --git a/src/test/ui/issues/issue-69683.stderr b/src/test/ui/issues/issue-69683.stderr
index b53923eec1d..9c71ecffa26 100644
--- a/src/test/ui/issues/issue-69683.stderr
+++ b/src/test/ui/issues/issue-69683.stderr
@@ -8,7 +8,7 @@ error[E0283]: type annotations needed
   --> $DIR/issue-69683.rs:30:10
    |
 LL |     0u16.foo(b);
-   |          ^^^ cannot infer type for type parameter `I` declared on the trait `Foo`
+   |          ^^^
    |
 note: multiple `impl`s satisfying `u8: Element<_>` found
   --> $DIR/issue-69683.rs:5:1
@@ -26,6 +26,10 @@ LL |     u8: Element<I>,
 LL | {
 LL |     fn foo(self, x: <u8 as Element<I>>::Array);
    |        --- required by a bound in this
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <u16 as Foo<I>>::foo(0u16, b);
+   |     +++++++++++++++++++++    ~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-72690.stderr b/src/test/ui/issues/issue-72690.stderr
index f1ec678b201..9edf14ef291 100644
--- a/src/test/ui/issues/issue-72690.stderr
+++ b/src/test/ui/issues/issue-72690.stderr
@@ -12,51 +12,60 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:7:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0282]: type annotations needed
   --> $DIR/issue-72690.rs:12:6
    |
 LL |     |x| String::from("x".as_ref());
-   |      ^ consider giving this closure parameter a type
+   |      ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     |x: _| String::from("x".as_ref());
+   |       +++
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:12:26
    |
 LL |     |x| String::from("x".as_ref());
-   |                      ----^^^^^^--
-   |                      |   |
-   |                      |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                      this method call resolves to `&T`
+   |                          ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     |x| String::from(<str as AsRef<T>>::as_ref("x"));
+   |                      ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed for `&T`
-  --> $DIR/issue-72690.rs:17:17
+  --> $DIR/issue-72690.rs:17:9
    |
 LL |     let _ = "x".as_ref();
-   |         -       ^^^^^^ cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |         |
-   |         consider giving this pattern the explicit type `&T`, where the type parameter `T` is specified
+   |         ^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let _: &T = "x".as_ref();
+   |          ++++
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:21:5
@@ -72,16 +81,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:21:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:28:5
@@ -97,16 +107,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:28:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:37:5
@@ -122,16 +133,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:37:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:46:5
@@ -147,16 +159,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:46:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:53:5
@@ -172,16 +185,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:53:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:62:5
@@ -197,16 +211,17 @@ error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:62:22
    |
 LL |     String::from("x".as_ref());
-   |                  ----^^^^^^--
-   |                  |   |
-   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |                  this method call resolves to `&T`
+   |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
            - impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     String::from(<str as AsRef<T>>::as_ref("x"));
+   |                  ++++++++++++++++++++++++++   ~
 
 error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/issues/issue-7813.stderr b/src/test/ui/issues/issue-7813.stderr
index 59be0f3be11..3aee61bd5a5 100644
--- a/src/test/ui/issues/issue-7813.stderr
+++ b/src/test/ui/issues/issue-7813.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `&[_; 0]`
-  --> $DIR/issue-7813.rs:2:13
+  --> $DIR/issue-7813.rs:2:9
    |
 LL |     let v = &[];
-   |         -   ^^^ cannot infer type
-   |         |
-   |         consider giving `v` the explicit type `&[_; 0]`, with the type parameters specified
+   |         ^
+   |
+help: consider giving `v` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let v: &[_; 0] = &[];
+   |          +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/match/match-unresolved-one-arm.stderr b/src/test/ui/match/match-unresolved-one-arm.stderr
index 77df9921b75..9eadb88a8ba 100644
--- a/src/test/ui/match/match-unresolved-one-arm.stderr
+++ b/src/test/ui/match/match-unresolved-one-arm.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/match-unresolved-one-arm.rs:4:9
    |
 LL |     let x = match () {
-   |         ^ consider giving `x` a type
+   |         ^
+   |
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _ = match () {
+   |          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index f33672433de..66e7ada3ac5 100644
--- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
+  --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
    |
 LL |     let mut x = Vec::new();
-   |         -----   ^^^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |         ^^^^^
+   |
+help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let mut x: Vec<T> = Vec::new();
+   |              ++++++++
 
 error[E0283]: type annotations needed
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
diff --git a/src/test/ui/missing/missing-items/missing-type-parameter.stderr b/src/test/ui/missing/missing-items/missing-type-parameter.stderr
index 2aa2b0e6a3c..722539fca6b 100644
--- a/src/test/ui/missing/missing-items/missing-type-parameter.stderr
+++ b/src/test/ui/missing/missing-items/missing-type-parameter.stderr
@@ -2,13 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/missing-type-parameter.rs:4:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for type parameter `X` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `X` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/missing-type-parameter.rs:1:8
+help: consider specifying the generic argument
    |
-LL | fn foo<X>() { }
-   |        ^
+LL |     foo::<X>();
+   |        +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr b/src/test/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr
index 34f1397ce1d..85c9fe409db 100644
--- a/src/test/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr
+++ b/src/test/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr
@@ -116,7 +116,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:14
    |
 LL |         V = [Vec::new; { [0].len() ].len() as isize,
-   |              ^^^^^^^^ cannot infer type for type parameter `T`
+   |              ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
+   |
+help: consider specifying the generic argument
+   |
+LL |         V = [Vec::<T>::new; { [0].len() ].len() as isize,
+   |                 +++++
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
index 427234e97cf..bad241634cb 100644
--- a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
+++ b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
@@ -40,24 +40,26 @@ LL |   let v : Vec<'a> = vec![];
    |                 +
 
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:25
+  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:7
    |
 LL |   let v : Vec<(u32,_) = vec![];
-   |       -                 ^^^^^^ cannot infer type for type parameter `T`
-   |       |
-   |       consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |       ^
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |   let v: Vec<T> : Vec<(u32,_) = vec![];
+   |        ++++++++
 
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:20
+  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:7
    |
 LL |   let v : Vec<'a = vec![];
-   |       -            ^^^^^^ cannot infer type for type parameter `T`
-   |       |
-   |       consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |       ^
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |   let v: Vec<T> : Vec<'a = vec![];
+   |        ++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/pattern/pat-tuple-bad-type.rs b/src/test/ui/pattern/pat-tuple-bad-type.rs
index 01e793e8685..98481167a59 100644
--- a/src/test/ui/pattern/pat-tuple-bad-type.rs
+++ b/src/test/ui/pattern/pat-tuple-bad-type.rs
@@ -1,8 +1,8 @@
 fn main() {
-    let x;
+    let x; //~ ERROR type annotations needed
 
     match x {
-        (..) => {} //~ ERROR type annotations needed
+        (..) => {}
         _ => {}
     }
 
diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr
index 598b6a3794e..11b28987848 100644
--- a/src/test/ui/pattern/pat-tuple-bad-type.stderr
+++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr
@@ -1,13 +1,14 @@
 error[E0282]: type annotations needed
-  --> $DIR/pat-tuple-bad-type.rs:5:9
+  --> $DIR/pat-tuple-bad-type.rs:2:9
    |
 LL |     let x;
-   |         - consider giving `x` a type
-...
-LL |         (..) => {}
-   |         ^^^^ cannot infer type
+   |         ^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let x: _;
+   |          +++
 
 error[E0308]: mismatched types
   --> $DIR/pat-tuple-bad-type.rs:10:9
diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr
index 06b6e80b44f..e6a4e5f19b7 100644
--- a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr
+++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr
@@ -189,7 +189,12 @@ error[E0282]: type annotations needed
   --> $DIR/rest-pat-semantic-disallowed.rs:33:9
    |
 LL |     let x @ ..;
-   |         ^^^^^^ consider giving this pattern a type
+   |         ^^^^^^
+   |
+help: consider giving this pattern a type
+   |
+LL |     let x @ ..: _;
+   |               +++
 
 error: aborting due to 23 previous errors
 
diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr
index f475c26f32b..f839dd927db 100644
--- a/src/test/ui/resolve/issue-85348.stderr
+++ b/src/test/ui/resolve/issue-85348.stderr
@@ -17,7 +17,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-85348.rs:6:13
    |
 LL |         let mut N;
-   |             ^^^^^ consider giving `N` a type
+   |             ^^^^^
+   |
+help: consider giving `N` an explicit type
+   |
+LL |         let mut N: _;
+   |                  +++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr
index 278d0492244..cd3ffdc6f9d 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr
@@ -1,20 +1,26 @@
-error[E0282]: type annotations needed for `Option<_>`
-  --> $DIR/issue-42234-unknown-receiver-type.rs:10:7
+error[E0282]: type annotations needed
+  --> $DIR/issue-42234-unknown-receiver-type.rs:9:24
    |
 LL |     let x: Option<_> = None;
-   |         - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified
-LL |     x.unwrap().method_that_could_exist_on_some_type();
-   |       ^^^^^^ cannot infer type for type parameter `T`
+   |                        ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |     let x: Option<_> = None::<T>;
+   |                            +++++
 
 error[E0282]: type annotations needed
-  --> $DIR/issue-42234-unknown-receiver-type.rs:16:10
+  --> $DIR/issue-42234-unknown-receiver-type.rs:15:10
    |
 LL |         .sum::<_>()
-   |          ^^^ cannot infer type
+   |          ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |         .sum::<_>()
+   |             ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr
index 8d4ed4aea6a..b6a3f07f571 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr
@@ -1,20 +1,26 @@
-error[E0282]: type annotations needed for `Option<_>`
-  --> $DIR/issue-42234-unknown-receiver-type.rs:10:7
+error[E0282]: type annotations needed
+  --> $DIR/issue-42234-unknown-receiver-type.rs:9:24
    |
 LL |     let x: Option<_> = None;
-   |         - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified
-LL |     x.unwrap().method_that_could_exist_on_some_type();
-   |       ^^^^^^ cannot infer type for type parameter `T`
+   |                        ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |     let x: Option<_> = None::<T>;
+   |                            +++++
 
 error[E0282]: type annotations needed
-  --> $DIR/issue-42234-unknown-receiver-type.rs:16:16
+  --> $DIR/issue-42234-unknown-receiver-type.rs:15:10
    |
 LL |         .sum::<_>()
-   |                ^ cannot infer type for type parameter `S` declared on the associated function `sum`
+   |          ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
    = note: type must be known at this point
+help: consider specifying the generic argument
+   |
+LL |         .sum::<S>()
+   |             ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.rs b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
index 15b00de44b9..fd53121204c 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.rs
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
@@ -6,9 +6,8 @@
 // the fix of which this tests).
 
 fn shines_a_beacon_through_the_darkness() {
-    let x: Option<_> = None;
+    let x: Option<_> = None; //~ ERROR type annotations needed
     x.unwrap().method_that_could_exist_on_some_type();
-    //~^ ERROR type annotations needed
 }
 
 fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
diff --git a/src/test/ui/span/method-and-field-eager-resolution.rs b/src/test/ui/span/method-and-field-eager-resolution.rs
index a38f07d58e4..a0f0d8810e5 100644
--- a/src/test/ui/span/method-and-field-eager-resolution.rs
+++ b/src/test/ui/span/method-and-field-eager-resolution.rs
@@ -2,14 +2,14 @@
 
 fn main() {
     let mut x = Default::default();
-    x.0;
     //~^ ERROR type annotations needed
+    x.0;
     x = 1;
 }
 
 fn foo() {
     let mut x = Default::default();
-    x[0];
     //~^ ERROR type annotations needed
+    x[0];
     x = 1;
 }
diff --git a/src/test/ui/span/method-and-field-eager-resolution.stderr b/src/test/ui/span/method-and-field-eager-resolution.stderr
index 0ecbe4c136e..2dd650f38ce 100644
--- a/src/test/ui/span/method-and-field-eager-resolution.stderr
+++ b/src/test/ui/span/method-and-field-eager-resolution.stderr
@@ -1,22 +1,26 @@
 error[E0282]: type annotations needed
-  --> $DIR/method-and-field-eager-resolution.rs:5:5
+  --> $DIR/method-and-field-eager-resolution.rs:4:9
    |
 LL |     let mut x = Default::default();
-   |         ----- consider giving `x` a type
-LL |     x.0;
-   |     ^ cannot infer type
+   |         ^^^^^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let mut x: _ = Default::default();
+   |              +++
 
 error[E0282]: type annotations needed
-  --> $DIR/method-and-field-eager-resolution.rs:12:5
+  --> $DIR/method-and-field-eager-resolution.rs:11:9
    |
 LL |     let mut x = Default::default();
-   |         ----- consider giving `x` a type
-LL |     x[0];
-   |     ^ cannot infer type
+   |         ^^^^^
    |
    = note: type must be known at this point
+help: consider giving `x` an explicit type
+   |
+LL |     let mut x: _ = Default::default();
+   |              +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr
index fbfbefd0782..e4a8f746462 100644
--- a/src/test/ui/span/type-annotations-needed-expr.stderr
+++ b/src/test/ui/span/type-annotations-needed-expr.stderr
@@ -2,10 +2,10 @@ error[E0282]: type annotations needed
   --> $DIR/type-annotations-needed-expr.rs:2:39
    |
 LL |     let _ = (vec![1,2,3]).into_iter().sum() as f64;
-   |                                       ^^^ cannot infer type for type parameter `S` declared on the associated function `sum`
+   |                                       ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
    = note: type must be known at this point
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
    |
 LL |     let _ = (vec![1,2,3]).into_iter().sum::<S>() as f64;
    |                                          +++++
diff --git a/src/test/ui/suggestions/fn-needing-specified-return-type-param.rs b/src/test/ui/suggestions/fn-needing-specified-return-type-param.rs
index 2f140f823af..bcc91b5cb4c 100644
--- a/src/test/ui/suggestions/fn-needing-specified-return-type-param.rs
+++ b/src/test/ui/suggestions/fn-needing-specified-return-type-param.rs
@@ -1,5 +1,7 @@
 fn f<A>() -> A { unimplemented!() }
 fn foo() {
-    let _ = f; //~ ERROR type annotations needed for `fn() -> A`
+    let _ = f;
+    //~^ ERROR type annotations needed
+    //~| HELP consider specifying the generic argument
 }
 fn main() {}
diff --git a/src/test/ui/suggestions/fn-needing-specified-return-type-param.stderr b/src/test/ui/suggestions/fn-needing-specified-return-type-param.stderr
index a4cfee55633..9dea667fb96 100644
--- a/src/test/ui/suggestions/fn-needing-specified-return-type-param.stderr
+++ b/src/test/ui/suggestions/fn-needing-specified-return-type-param.stderr
@@ -1,16 +1,13 @@
-error[E0282]: type annotations needed for `fn() -> A`
+error[E0282]: type annotations needed
   --> $DIR/fn-needing-specified-return-type-param.rs:3:13
    |
 LL |     let _ = f;
-   |         -   ^ cannot infer type for type parameter `A` declared on the function `f`
-   |         |
-   |         consider giving this pattern the explicit type `fn() -> A`, where the type parameter `A` is specified
+   |             ^ cannot infer type of the type parameter `A` declared on the function `f`
    |
-help: type parameter declared here
-  --> $DIR/fn-needing-specified-return-type-param.rs:1:6
+help: consider specifying the generic argument
    |
-LL | fn f<A>() -> A { unimplemented!() }
-   |      ^
+LL |     let _ = f::<A>;
+   |              +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/suggest-closure-return-type-1.rs b/src/test/ui/suggestions/suggest-closure-return-type-1.rs
index 910f273b972..8bb4219039b 100644
--- a/src/test/ui/suggestions/suggest-closure-return-type-1.rs
+++ b/src/test/ui/suggestions/suggest-closure-return-type-1.rs
@@ -1,3 +1,7 @@
+fn unbound_drop(_: impl Sized) {}
+
 fn main() {
-    let _v = || -> _ { [] }; //~ ERROR type annotations needed for the closure
+    unbound_drop(|| -> _ { [] });
+    //~^ ERROR type annotations needed for `[_; 0]`
+    //~| HELP try giving this closure an explicit return type
 }
diff --git a/src/test/ui/suggestions/suggest-closure-return-type-1.stderr b/src/test/ui/suggestions/suggest-closure-return-type-1.stderr
index 7161ca3903e..3116211b52c 100644
--- a/src/test/ui/suggestions/suggest-closure-return-type-1.stderr
+++ b/src/test/ui/suggestions/suggest-closure-return-type-1.stderr
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
-  --> $DIR/suggest-closure-return-type-1.rs:2:24
+error[E0282]: type annotations needed for `[_; 0]`
+  --> $DIR/suggest-closure-return-type-1.rs:4:18
    |
-LL |     let _v = || -> _ { [] };
-   |                        ^^ cannot infer type
+LL |     unbound_drop(|| -> _ { [] });
+   |                  ^^^^^^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
-LL |     let _v = || -> [_; 0] { [] };
-   |                    ~~~~~~
+LL |     unbound_drop(|| -> [_; 0] { [] });
+   |                        ~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/suggest-closure-return-type-2.rs b/src/test/ui/suggestions/suggest-closure-return-type-2.rs
index 6955b37ad97..25ed1882e8d 100644
--- a/src/test/ui/suggestions/suggest-closure-return-type-2.rs
+++ b/src/test/ui/suggestions/suggest-closure-return-type-2.rs
@@ -1,3 +1,7 @@
+fn unbound_drop(_: impl Sized) {}
+
 fn main() {
-    let _v = || { [] }; //~ ERROR type annotations needed for the closure
+    unbound_drop(|| { [] })
+    //~^ ERROR type annotations needed for `[_; 0]`
+    //~| HELP try giving this closure an explicit return type
 }
diff --git a/src/test/ui/suggestions/suggest-closure-return-type-2.stderr b/src/test/ui/suggestions/suggest-closure-return-type-2.stderr
index a7f5b58c4da..f368e7de467 100644
--- a/src/test/ui/suggestions/suggest-closure-return-type-2.stderr
+++ b/src/test/ui/suggestions/suggest-closure-return-type-2.stderr
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
-  --> $DIR/suggest-closure-return-type-2.rs:2:19
+error[E0282]: type annotations needed for `[_; 0]`
+  --> $DIR/suggest-closure-return-type-2.rs:4:18
    |
-LL |     let _v = || { [] };
-   |                   ^^ cannot infer type
+LL |     unbound_drop(|| { [] })
+   |                  ^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
-LL |     let _v = || -> [_; 0] { [] };
-   |                 +++++++++
+LL |     unbound_drop(|| -> [_; 0] { [] })
+   |                     +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/suggest-closure-return-type-3.rs b/src/test/ui/suggestions/suggest-closure-return-type-3.rs
index ec6c094027e..3de6c55cf16 100644
--- a/src/test/ui/suggestions/suggest-closure-return-type-3.rs
+++ b/src/test/ui/suggestions/suggest-closure-return-type-3.rs
@@ -1,3 +1,7 @@
+fn unbound_drop(_: impl Sized) {}
+
 fn main() {
-    let _v = || []; //~ ERROR type annotations needed for the closure
+    unbound_drop(|| []);
+    //~^ ERROR type annotations needed for `[_; 0]`
+    //~| HELP try giving this closure an explicit return type
 }
diff --git a/src/test/ui/suggestions/suggest-closure-return-type-3.stderr b/src/test/ui/suggestions/suggest-closure-return-type-3.stderr
index eeec23e0da0..41769321533 100644
--- a/src/test/ui/suggestions/suggest-closure-return-type-3.stderr
+++ b/src/test/ui/suggestions/suggest-closure-return-type-3.stderr
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
-  --> $DIR/suggest-closure-return-type-3.rs:2:17
+error[E0282]: type annotations needed for `[_; 0]`
+  --> $DIR/suggest-closure-return-type-3.rs:4:18
    |
-LL |     let _v = || [];
-   |                 ^^ cannot infer type
+LL |     unbound_drop(|| []);
+   |                  ^^
    |
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
    |
-LL |     let _v = || -> [_; 0] { [] };
-   |                 +++++++++++    +
+LL |     unbound_drop(|| -> [_; 0] { [] });
+   |                     +++++++++++    +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr b/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr
index 0e52420ec43..57b2587ae5c 100644
--- a/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr
+++ b/src/test/ui/traits/do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr
@@ -2,19 +2,18 @@ error[E0282]: type annotations needed
   --> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
    |
 LL |     thing.method(42);
-   |     ------^^^^^^----
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
+   |           ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing<bool> as Method<T>>::method(thing, 42);
+   |     +++++++++++++++++++++++++++++++++++     ~
 
 error[E0283]: type annotations needed
   --> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
    |
 LL |     thing.method(42);
-   |     ------^^^^^^----
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
+   |           ^^^^^^
    |
 note: multiple `impl`s satisfying `Thing<bool>: Method<_>` found
   --> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:7:1
@@ -24,12 +23,10 @@ LL | impl<X> Method<i32> for Thing<X> {
 ...
 LL | impl<X> Method<u32> for Thing<X> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
+help: try using a fully qualified path to specify the expected types
    |
-LL |     <Thing<_> as Method<i32>>::method(thing, 42);
-   |     ++++++++++++++++++++++++++++++++++     ~
-LL |     <Thing<_> as Method<u32>>::method(thing, 42);
-   |     ++++++++++++++++++++++++++++++++++     ~
+LL |     <Thing<bool> as Method<T>>::method(thing, 42);
+   |     +++++++++++++++++++++++++++++++++++     ~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr
index 63c1cb3791e..5aa42b5b1d3 100644
--- a/src/test/ui/traits/issue-77982.stderr
+++ b/src/test/ui/traits/issue-77982.stderr
@@ -2,9 +2,7 @@ error[E0283]: type annotations needed
   --> $DIR/issue-77982.rs:8:10
    |
 LL |     opts.get(opt.as_ref());
-   |          ^^^ ------------ this method call resolves to `&T`
-   |          |
-   |          cannot infer type for type parameter `Q` declared on the associated function `get`
+   |          ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
    |
    = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
            - impl Borrow<str> for String;
@@ -15,44 +13,36 @@ note: required by a bound in `HashMap::<K, V, S>::get`
    |
 LL |         K: Borrow<Q>,
    |            ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
+help: consider specifying the generic argument
+   |
+LL |     opts.get::<Q>(opt.as_ref());
+   |             +++++
 help: consider specifying the type argument in the function call
    |
 LL |     opts.get::<Q>(opt.as_ref());
    |             +++++
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-77982.rs:8:18
+  --> $DIR/issue-77982.rs:8:10
    |
 LL |     opts.get(opt.as_ref());
-   |              ----^^^^^^--
-   |              |   |
-   |              |   cannot infer type for type parameter `T` declared on the trait `AsRef`
-   |              this method call resolves to `&T`
+   |          ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
    |
    = note: multiple `impl`s satisfying `String: AsRef<_>` found in the following crates: `alloc`, `std`:
            - impl AsRef<OsStr> for String;
            - impl AsRef<Path> for String;
            - impl AsRef<[u8]> for String;
            - impl AsRef<str> for String;
-help: use the fully qualified path for the potential candidates
+help: consider specifying the generic argument
    |
-LL |     opts.get(<String as AsRef<OsStr>>::as_ref(opt));
-   |              +++++++++++++++++++++++++++++++++   ~
-LL |     opts.get(<String as AsRef<Path>>::as_ref(opt));
-   |              ++++++++++++++++++++++++++++++++   ~
-LL |     opts.get(<String as AsRef<[u8]>>::as_ref(opt));
-   |              ++++++++++++++++++++++++++++++++   ~
-LL |     opts.get(<String as AsRef<str>>::as_ref(opt));
-   |              +++++++++++++++++++++++++++++++   ~
-     and 4 other candidates
+LL |     opts.get::<Q>(opt.as_ref());
+   |             +++++
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-77982.rs:13:44
+  --> $DIR/issue-77982.rs:13:59
    |
 LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
-   |                                            ^^^^^^^^^ ----------- this method call resolves to `T`
-   |                                            |
-   |                                            cannot infer type for type parameter `T` declared on the trait `From`
+   |                                                           ^^^^
    |
    = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
            - impl From<Ipv4Addr> for u32;
@@ -60,14 +50,16 @@ LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
            - impl From<bool> for u32;
            - impl From<char> for u32;
            and 3 more
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
+   |                                                      +++++++++++++++++++++++    ~
 
 error[E0283]: type annotations needed for `Box<T>`
-  --> $DIR/issue-77982.rs:36:16
+  --> $DIR/issue-77982.rs:36:9
    |
 LL |     let _ = ().foo();
-   |         -      ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
-   |         |
-   |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+   |         ^
    |
 note: multiple `impl`s satisfying `(): Foo<'_, _>` found
   --> $DIR/issue-77982.rs:29:1
@@ -76,14 +68,16 @@ LL | impl Foo<'static, u32> for () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL | impl<'a> Foo<'a, i16> for () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let _: Box<T> = ().foo();
+   |          ++++++++
 
 error[E0283]: type annotations needed for `Box<T>`
-  --> $DIR/issue-77982.rs:40:19
+  --> $DIR/issue-77982.rs:40:9
    |
 LL |     let _ = (&()).bar();
-   |         -         ^^^ cannot infer type for type parameter `T` declared on the trait `Bar`
-   |         |
-   |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+   |         ^
    |
 note: multiple `impl`s satisfying `&(): Bar<'_, _>` found
   --> $DIR/issue-77982.rs:32:1
@@ -92,6 +86,10 @@ LL | impl<'a> Bar<'static, u32> for &'a () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL | impl<'a> Bar<'a, i16> for &'a () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let _: Box<T> = (&()).bar();
+   |          ++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr b/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr
index da746134710..25f8d538377 100644
--- a/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr
+++ b/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr
@@ -2,25 +2,19 @@ error[E0282]: type annotations needed
   --> $DIR/multidispatch-convert-ambig-dest.rs:26:5
    |
 LL |     test(22, std::default::Default::default());
-   |     ^^^^ cannot infer type for type parameter `U` declared on the function `test`
+   |     ^^^^ cannot infer type of the type parameter `U` declared on the function `test`
    |
-help: type parameter declared here
-  --> $DIR/multidispatch-convert-ambig-dest.rs:20:11
+help: consider specifying the generic arguments
    |
-LL | fn test<T,U>(_: T, _: U)
-   |           ^
+LL |     test::<i32, U>(22, std::default::Default::default());
+   |         ++++++++++
 
 error[E0283]: type annotations needed
   --> $DIR/multidispatch-convert-ambig-dest.rs:26:5
    |
 LL |     test(22, std::default::Default::default());
-   |     ^^^^ cannot infer type for type parameter `U` declared on the function `test`
+   |     ^^^^ cannot infer type of the type parameter `U` declared on the function `test`
    |
-help: type parameter declared here
-  --> $DIR/multidispatch-convert-ambig-dest.rs:20:11
-   |
-LL | fn test<T,U>(_: T, _: U)
-   |           ^
 note: multiple `impl`s satisfying `i32: Convert<_>` found
   --> $DIR/multidispatch-convert-ambig-dest.rs:8:1
    |
@@ -36,6 +30,10 @@ LL | fn test<T,U>(_: T, _: U)
    |    ---- required by a bound in this
 LL | where T : Convert<U>
    |           ^^^^^^^^^^ required by this bound in `test`
+help: consider specifying the generic arguments
+   |
+LL |     test::<i32, U>(22, std::default::Default::default());
+   |         ++++++++++
 help: consider specifying the type arguments in the function call
    |
 LL |     test::<T, U>(22, std::default::Default::default());
diff --git a/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr b/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr
index 3c8d7450f96..75d45d9052b 100644
--- a/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr
+++ b/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr
@@ -2,25 +2,19 @@ error[E0282]: type annotations needed
   --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
    |
 LL |     a.method();
-   |     --^^^^^^--
-   |     | |
-   |     | cannot infer type for type parameter `U` declared on the trait `V`
-   |     this method call resolves to `U`
+   |       ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <A<B> as V<U>>::method(a);
+   |     +++++++++++++++++++++++ ~
 
 error[E0283]: type annotations needed
   --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
    |
 LL |     a.method();
-   |     --^^^^^^--
-   |     | |
-   |     | cannot infer type for type parameter `U`
-   |     this method call resolves to `U`
+   |       ^^^^^^
    |
-help: type parameter declared here
-  --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:12:9
-   |
-LL | impl<T, U> V<U> for A<T>
-   |         ^
 note: multiple `impl`s satisfying `B: I<_>` found
   --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:5:1
    |
@@ -33,6 +27,10 @@ note: required because of the requirements on the impl of `V<_>` for `A<B>`
    |
 LL | impl<T, U> V<U> for A<T>
    |            ^^^^     ^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <A<B> as V<U>>::method(a);
+   |     +++++++++++++++++++++++ ~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.rs b/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.rs
new file mode 100644
index 00000000000..9a2cf469d08
--- /dev/null
+++ b/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.rs
@@ -0,0 +1,60 @@
+use std::ops::{Deref, DerefMut};
+
+struct Thing;
+
+trait Method<T> {
+    fn method(&self) -> T;
+    fn mut_method(&mut self) -> T;
+}
+
+impl Method<i32> for Thing {
+    fn method(&self) -> i32 { 0 }
+    fn mut_method(&mut self) -> i32 { 0 }
+}
+
+impl Method<u32> for Thing {
+    fn method(&self) -> u32 { 0 }
+    fn mut_method(&mut self) -> u32 { 0 }
+}
+trait MethodRef<T> {
+    fn by_self(self);
+}
+impl MethodRef<i32> for &Thing {
+    fn by_self(self) {}
+}
+impl MethodRef<u32> for &Thing {
+    fn by_self(self) {}
+}
+
+
+struct DerefsTo<T>(T);
+impl<T> Deref for DerefsTo<T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl<T> DerefMut for DerefsTo<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+fn main() {
+    let mut thing = Thing;
+    thing.method();
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
+    thing.mut_method(); //~ ERROR type annotations needed
+    thing.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_to = DerefsTo(Thing);
+    deref_to.method(); //~ ERROR type annotations needed
+    deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_to.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_deref_to = DerefsTo(DerefsTo(Thing));
+    deref_deref_to.method(); //~ ERROR type annotations needed
+    deref_deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_deref_to.by_self(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.stderr b/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.stderr
new file mode 100644
index 00000000000..68b31a1ca34
--- /dev/null
+++ b/src/test/ui/traits/suggest-fully-qualified-path-with-adjustment.stderr
@@ -0,0 +1,186 @@
+error[E0282]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:45:11
+   |
+LL |     thing.method();
+   |           ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&thing);
+   |     ++++++++++++++++++++++++++++++     ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:45:11
+   |
+LL |     thing.method();
+   |           ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&thing);
+   |     ++++++++++++++++++++++++++++++     ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:48:11
+   |
+LL |     thing.mut_method();
+   |           ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(&mut thing);
+   |     +++++++++++++++++++++++++++++++++++++      ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:49:11
+   |
+LL |     thing.by_self();
+   |           ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(&thing);
+   |     +++++++++++++++++++++++++++++++++++     ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:52:14
+   |
+LL |     deref_to.method();
+   |              ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&deref_to);
+   |     ++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:53:14
+   |
+LL |     deref_to.mut_method();
+   |              ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(&mut deref_to);
+   |     +++++++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:54:14
+   |
+LL |     deref_to.by_self();
+   |              ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(&deref_to);
+   |     +++++++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:57:20
+   |
+LL |     deref_deref_to.method();
+   |                    ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(&deref_deref_to);
+   |     ++++++++++++++++++++++++++++++              ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:58:20
+   |
+LL |     deref_deref_to.mut_method();
+   |                    ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(&mut deref_deref_to);
+   |     +++++++++++++++++++++++++++++++++++++               ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:59:20
+   |
+LL |     deref_deref_to.by_self();
+   |                    ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(&deref_deref_to);
+   |     +++++++++++++++++++++++++++++++++++              ~
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs
deleted file mode 100644
index da68b996be9..00000000000
--- a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-struct Thing;
-
-trait Method<T> {
-    fn method(&self) -> T;
-    fn mut_method(&mut self) -> T;
-}
-
-impl Method<i32> for Thing {
-    fn method(&self) -> i32 { 0 }
-    fn mut_method(&mut self) -> i32 { 0 }
-}
-
-impl Method<u32> for Thing {
-    fn method(&self) -> u32 { 0 }
-    fn mut_method(&mut self) -> u32 { 0 }
-}
-
-fn main() {
-    let thing = Thing;
-    thing.method();
-    //~^ ERROR type annotations needed
-    //~| ERROR type annotations needed
-    thing.mut_method(); //~ ERROR type annotations needed
-}
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr
deleted file mode 100644
index 0c4962417e9..00000000000
--- a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr
+++ /dev/null
@@ -1,61 +0,0 @@
-error[E0282]: type annotations needed
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11
-   |
-LL |     thing.method();
-   |     ------^^^^^^--
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
-
-error[E0283]: type annotations needed
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11
-   |
-LL |     thing.method();
-   |     ------^^^^^^--
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
-   |
-note: multiple `impl`s satisfying `Thing: Method<_>` found
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1
-   |
-LL | impl Method<i32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | impl Method<u32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
-   |
-LL |     <Thing as Method<i32>>::method(&thing);
-   |     ++++++++++++++++++++++++++++++++     ~
-LL |     <Thing as Method<u32>>::method(&thing);
-   |     ++++++++++++++++++++++++++++++++     ~
-
-error[E0283]: type annotations needed
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:23:11
-   |
-LL |     thing.mut_method();
-   |     ------^^^^^^^^^^--
-   |     |     |
-   |     |     cannot infer type for type parameter `T` declared on the trait `Method`
-   |     this method call resolves to `T`
-   |
-note: multiple `impl`s satisfying `Thing: Method<_>` found
-  --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1
-   |
-LL | impl Method<i32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | impl Method<u32> for Thing {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
-   |
-LL |     <Thing as Method<i32>>::mut_method(&mut thing);
-   |     +++++++++++++++++++++++++++++++++++++++      ~
-LL |     <Thing as Method<u32>>::mut_method(&mut thing);
-   |     +++++++++++++++++++++++++++++++++++++++      ~
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.rs b/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.rs
new file mode 100644
index 00000000000..da640c8c8c2
--- /dev/null
+++ b/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.rs
@@ -0,0 +1,64 @@
+use std::ops::{Deref, DerefMut};
+
+struct Thing;
+
+trait Method<T> {
+    fn method(&self) -> T;
+    fn mut_method(&mut self) -> T;
+}
+
+impl Method<i32> for Thing {
+    fn method(&self) -> i32 { 0 }
+    fn mut_method(&mut self) -> i32 { 0 }
+}
+
+impl Method<u32> for Thing {
+    fn method(&self) -> u32 { 0 }
+    fn mut_method(&mut self) -> u32 { 0 }
+}
+
+trait MethodRef<T> {
+    fn by_self(self);
+}
+impl MethodRef<i32> for &Thing {
+    fn by_self(self) {}
+}
+impl MethodRef<u32> for &Thing {
+    fn by_self(self) {}
+}
+
+struct DerefsTo<T>(T);
+impl<T> Deref for DerefsTo<T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl<T> DerefMut for DerefsTo<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+fn main() {
+    let mut ref_thing = &Thing;
+    ref_thing.method();
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
+    ref_thing.by_self(); //~ ERROR type annotations needed
+
+    let mut mut_thing = &mut Thing;
+    mut_thing.method(); //~ ERROR type annotations needed
+    mut_thing.mut_method(); //~ ERROR type annotations needed
+    mut_thing.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_to = &DerefsTo(Thing);
+    deref_to.method(); //~ ERROR type annotations needed
+    deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_to.by_self(); //~ ERROR type annotations needed
+
+    let mut deref_deref_to = &DerefsTo(DerefsTo(Thing));
+    deref_deref_to.method(); //~ ERROR type annotations needed
+    deref_deref_to.mut_method(); //~ ERROR type annotations needed
+    deref_deref_to.by_self(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.stderr b/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.stderr
new file mode 100644
index 00000000000..27518a54e75
--- /dev/null
+++ b/src/test/ui/traits/suggest-fully-qualified-path-without-adjustment.stderr
@@ -0,0 +1,224 @@
+error[E0282]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:45:15
+   |
+LL |     ref_thing.method();
+   |               ^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(ref_thing);
+   |     +++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:45:15
+   |
+LL |     ref_thing.method();
+   |               ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(ref_thing);
+   |     +++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:48:15
+   |
+LL |     ref_thing.by_self();
+   |               ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(ref_thing);
+   |     ++++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:51:15
+   |
+LL |     mut_thing.method();
+   |               ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(mut_thing);
+   |     +++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:52:15
+   |
+LL |     mut_thing.mut_method();
+   |               ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(mut_thing);
+   |     +++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:53:15
+   |
+LL |     mut_thing.by_self();
+   |               ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(mut_thing);
+   |     ++++++++++++++++++++++++++++++++++         ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:56:14
+   |
+LL |     deref_to.method();
+   |              ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(deref_to);
+   |     +++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:57:14
+   |
+LL |     deref_to.mut_method();
+   |              ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(deref_to);
+   |     +++++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:58:14
+   |
+LL |     deref_to.by_self();
+   |              ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(deref_to);
+   |     ++++++++++++++++++++++++++++++++++        ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:61:20
+   |
+LL |     deref_deref_to.method();
+   |                    ^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::method(deref_deref_to);
+   |     +++++++++++++++++++++++++++++              ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:62:20
+   |
+LL |     deref_deref_to.mut_method();
+   |                    ^^^^^^^^^^
+   |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+   |
+LL | impl Method<i32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Thing as Method<T>>::mut_method(deref_deref_to);
+   |     +++++++++++++++++++++++++++++++++              ~
+
+error[E0283]: type annotations needed
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:63:20
+   |
+LL |     deref_deref_to.by_self();
+   |                    ^^^^^^^
+   |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+  --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+   |
+LL | impl MethodRef<i32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <&Thing as MethodRef<T>>::by_self(deref_deref_to);
+   |     ++++++++++++++++++++++++++++++++++              ~
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr
index cfa4a4b9d20..b3ca260894b 100644
--- a/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr
+++ b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr
@@ -2,9 +2,13 @@ error[E0282]: type annotations needed
   --> $DIR/closures_in_branches.rs:21:10
    |
 LL |         |x| x.len()
-   |          ^ consider giving this closure parameter a type
+   |          ^
    |
    = note: type must be known at this point
+help: consider giving this closure parameter an explicit type
+   |
+LL |         |x: _| x.len()
+   |           +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr b/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr
index 0cdd4cc8dc3..9a0e71b4eed 100644
--- a/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr
+++ b/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/incomplete-inference.rs:6:5
    |
 LL |     None
-   |     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL |     None::<T>
+   |         +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.stderr b/src/test/ui/type-inference/or_else-multiple-type-params.stderr
index 12a98e4d783..6ac63a91ee9 100644
--- a/src/test/ui/type-inference/or_else-multiple-type-params.stderr
+++ b/src/test/ui/type-inference/or_else-multiple-type-params.stderr
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed
-  --> $DIR/or_else-multiple-type-params.rs:7:10
+error[E0282]: type annotations needed for `Result<Child, F>`
+  --> $DIR/or_else-multiple-type-params.rs:7:18
    |
 LL |         .or_else(|err| {
-   |          ^^^^^^^ cannot infer type for type parameter `F` declared on the associated function `or_else`
+   |                  ^^^^^
    |
-help: consider specifying the type arguments in the method call
+help: try giving this closure an explicit return type
    |
-LL |         .or_else::<F, O>(|err| {
-   |                 ++++++++
+LL |         .or_else(|err| -> Result<Child, F> {
+   |                        +++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-inference/sort_by_key.stderr b/src/test/ui/type-inference/sort_by_key.stderr
index 78b7386c03e..0a48d5756eb 100644
--- a/src/test/ui/type-inference/sort_by_key.stderr
+++ b/src/test/ui/type-inference/sort_by_key.stderr
@@ -1,10 +1,10 @@
 error[E0282]: type annotations needed
-  --> $DIR/sort_by_key.rs:3:9
+  --> $DIR/sort_by_key.rs:3:40
    |
 LL |     lst.sort_by_key(|&(v, _)| v.iter().sum());
-   |         ^^^^^^^^^^^ cannot infer type for type parameter `K` declared on the associated function `sort_by_key`
+   |                                        ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
    |
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
    |
 LL |     lst.sort_by_key(|&(v, _)| v.iter().sum::<S>());
    |                                           +++++
diff --git a/src/test/ui/type-inference/unbounded-associated-type.stderr b/src/test/ui/type-inference/unbounded-associated-type.stderr
index 19e2bd4513d..e0fecc72f30 100644
--- a/src/test/ui/type-inference/unbounded-associated-type.stderr
+++ b/src/test/ui/type-inference/unbounded-associated-type.stderr
@@ -1,14 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/unbounded-associated-type.rs:15:5
+  --> $DIR/unbounded-associated-type.rs:15:7
    |
-LL |     type A;
-   |     ------- `<Self as T>::A` defined here
-...
 LL |     S(std::marker::PhantomData).foo();
-   |     ^--------------------------------
-   |     |
-   |     this method call resolves to `<Self as T>::A`
-   |     cannot infer type for type parameter `X` declared on the struct `S`
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
+   |
+help: consider specifying the generic argument
+   |
+LL |     S(std::marker::PhantomData::<T>).foo();
+   |                               +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
index 501fa7c8c67..209abfe5cba 100644
--- a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
@@ -2,13 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:8:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:3:8
+help: consider specifying the generic arguments
    |
-LL | fn foo<T, U = u64>() -> (T, U) {
-   |        ^
+LL |     foo::<T, U>();
+   |        ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
index d01c3a7d4e2..d92892eeb84 100644
--- a/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
@@ -2,13 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unbounded-type-param-in-fn.rs:6:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/unbounded-type-param-in-fn.rs:1:8
+help: consider specifying the generic argument
    |
-LL | fn foo<T>() -> T {
-   |        ^
+LL |     foo::<T>();
+   |        +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr
index 64fdbfe7db4..7d7890c8b80 100644
--- a/src/test/ui/type/type-annotation-needed.stderr
+++ b/src/test/ui/type/type-annotation-needed.stderr
@@ -2,19 +2,18 @@ error[E0283]: type annotations needed
   --> $DIR/type-annotation-needed.rs:6:5
    |
 LL |     foo(42);
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
    |
-help: type parameter declared here
-  --> $DIR/type-annotation-needed.rs:1:8
-   |
-LL | fn foo<T: Into<String>>(x: i32) {}
-   |        ^
    = note: cannot satisfy `_: Into<String>`
 note: required by a bound in `foo`
   --> $DIR/type-annotation-needed.rs:1:11
    |
 LL | fn foo<T: Into<String>>(x: i32) {}
    |           ^^^^^^^^^^^^ required by this bound in `foo`
+help: consider specifying the generic argument
+   |
+LL |     foo::<T>(42);
+   |        +++++
 help: consider specifying the type argument in the function call
    |
 LL |     foo::<T>(42);
diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr
index 8edec6e0ea3..d68d5e5d40b 100644
--- a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr
+++ b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr
@@ -1,10 +1,13 @@
 error[E0282]: type annotations needed for `[_; 0]`
-  --> $DIR/cannot_infer_local_or_array.rs:2:13
+  --> $DIR/cannot_infer_local_or_array.rs:2:9
    |
 LL |     let x = [];
-   |         -   ^^ cannot infer type
-   |         |
-   |         consider giving `x` the explicit type `[_; 0]`, with the type parameters specified
+   |         ^
+   |
+help: consider giving `x` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let x: [_; 0] = [];
+   |          ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
index 69a4af4672f..b63d2a3b61c 100644
--- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
+++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
@@ -1,12 +1,13 @@
 error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/cannot_infer_local_or_vec.rs:2:13
+  --> $DIR/cannot_infer_local_or_vec.rs:2:9
    |
 LL |     let x = vec![];
-   |         -   ^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+   |         ^
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let x: Vec<T> = vec![];
+   |          ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
index af7db439704..be60cda68b9 100644
--- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
+++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
@@ -1,12 +1,13 @@
 error[E0282]: type annotations needed for `(Vec<T>,)`
-  --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
+  --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
    |
 LL |     let (x, ) = (vec![], );
-   |         -----    ^^^^^^ cannot infer type for type parameter `T`
-   |         |
-   |         consider giving this pattern the explicit type `(Vec<T>,)`, where the type parameter `T` is specified
+   |         ^^^^^
    |
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+   |
+LL |     let (x, ): (Vec<T>,) = (vec![], );
+   |              +++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-check/unknown_type_for_closure.rs b/src/test/ui/type/type-check/unknown_type_for_closure.rs
index 0089d86e340..167687c1871 100644
--- a/src/test/ui/type/type-check/unknown_type_for_closure.rs
+++ b/src/test/ui/type/type-check/unknown_type_for_closure.rs
@@ -11,7 +11,7 @@ fn infer_ty() {
 }
 
 fn ambig_return() {
-    let x = || -> Vec<_> { Vec::new() }; //~ ERROR type annotations needed for the closure `fn() -> Vec<_>`
+    let x = || -> Vec<_> { Vec::new() }; //~ ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/src/test/ui/type/type-check/unknown_type_for_closure.stderr b/src/test/ui/type/type-check/unknown_type_for_closure.stderr
index c3accad5f25..9ae97f390d3 100644
--- a/src/test/ui/type/type-check/unknown_type_for_closure.stderr
+++ b/src/test/ui/type/type-check/unknown_type_for_closure.stderr
@@ -1,31 +1,36 @@
-error[E0282]: type annotations needed for `Vec<_>`
-  --> $DIR/unknown_type_for_closure.rs:2:14
+error[E0282]: type annotations needed
+  --> $DIR/unknown_type_for_closure.rs:2:13
    |
 LL |     let x = |b: Vec<_>| {};
-   |              ^ consider giving this closure parameter a type
+   |             ^^^^^^^^^^^^^^ cannot infer type for struct `Vec<_>`
 
 error[E0282]: type annotations needed
   --> $DIR/unknown_type_for_closure.rs:6:14
    |
 LL |     let x = |_| {};
-   |              ^ consider giving this closure parameter a type
+   |              ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     let x = |_: _| {};
+   |               +++
 
 error[E0282]: type annotations needed
   --> $DIR/unknown_type_for_closure.rs:10:14
    |
 LL |     let x = |k: _| {};
-   |              ^ consider giving this closure parameter a type
+   |              ^ cannot infer type
 
-error[E0282]: type annotations needed for the closure `fn() -> Vec<_>`
+error[E0282]: type annotations needed
   --> $DIR/unknown_type_for_closure.rs:14:28
    |
 LL |     let x = || -> Vec<_> { Vec::new() };
-   |                            ^^^^^^^^ cannot infer type for type parameter `T`
+   |                            ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
    |
-help: give this closure an explicit return type without `_` placeholders
+help: consider specifying the generic argument
    |
-LL |     let x = || -> Vec<_> { Vec::new() };
-   |                   ~~~~~~
+LL |     let x = || -> Vec<_> { Vec::<T>::new() };
+   |                               +++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr
index baf218243c4..c1ae10efac4 100644
--- a/src/test/ui/type/type-path-err-node-types.stderr
+++ b/src/test/ui/type/type-path-err-node-types.stderr
@@ -26,7 +26,12 @@ error[E0282]: type annotations needed
   --> $DIR/type-path-err-node-types.rs:23:14
    |
 LL |     let _ = |a, b: _| -> _ { 0 };
-   |              ^ consider giving this closure parameter a type
+   |              ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     let _ = |a: _, b: _| -> _ { 0 };
+   |               +++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/typeck/issue-65611.stderr b/src/test/ui/typeck/issue-65611.stderr
index e3c005a0593..5f831291a38 100644
--- a/src/test/ui/typeck/issue-65611.stderr
+++ b/src/test/ui/typeck/issue-65611.stderr
@@ -1,11 +1,8 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-65611.rs:59:20
+  --> $DIR/issue-65611.rs:59:13
    |
 LL |     let x = buffer.last().unwrap().0.clone();
-   |             -------^^^^--
-   |             |      |
-   |             |      cannot infer type for type parameter `T`
-   |             this method call resolves to `Option<&T>`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs
index d03001f5237..25c2dbe196f 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.rs
@@ -6,6 +6,7 @@
 
 fn a() {
     let mut closure0 = None;
+    //~^ ERROR type annotations needed
     let vec = vec![1, 2, 3];
 
     loop {
@@ -14,7 +15,6 @@ fn a() {
                 match closure0.take() {
                     Some(c) => {
                         return c();
-                        //~^ ERROR type annotations needed
                     }
                     None => { }
                 }
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr
index de20a38c447..666ab79b65c 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr
@@ -1,13 +1,14 @@
 error[E0282]: type annotations needed for `Option<T>`
-  --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32
+  --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:8:9
    |
 LL |     let mut closure0 = None;
-   |         ------------ consider giving `closure0` the explicit type `Option<T>`, with the type parameters specified
-...
-LL |                         return c();
-   |                                ^^^ cannot infer type
+   |         ^^^^^^^^^^^^
    |
    = note: type must be known at this point
+help: consider giving `closure0` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let mut closure0: Option<T> = None;
+   |                     +++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unconstrained-none.stderr b/src/test/ui/unconstrained-none.stderr
index fbd71bd091d..19ac74fdf58 100644
--- a/src/test/ui/unconstrained-none.stderr
+++ b/src/test/ui/unconstrained-none.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unconstrained-none.rs:4:5
    |
 LL |     None;
-   |     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+   |     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL |     None::<T>;
+   |         +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unconstrained-ref.stderr b/src/test/ui/unconstrained-ref.stderr
index eb8ebb5165d..1df6d8b446d 100644
--- a/src/test/ui/unconstrained-ref.stderr
+++ b/src/test/ui/unconstrained-ref.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/unconstrained-ref.rs:6:5
    |
 LL |     S { o: &None };
-   |     ^ cannot infer type for type parameter `T` declared on the struct `S`
+   |     ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `S`
+   |
+help: consider specifying the generic argument
+   |
+LL |     S::<T> { o: &None };
+   |      +++++
 
 error: aborting due to previous error