about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-09-26 12:58:17 +0200
committerGitHub <noreply@github.com>2020-09-26 12:58:17 +0200
commitac8169dc106f2005d41d969c114d85e8e53bce61 (patch)
tree8c48ca9c65f5818808b16ea9c60b54b7015a418e /compiler
parent31fd0ad69f0a007e02df1d562c78c60ed9be3292 (diff)
parent9a607c0a2781197b88ff2535b852b53d3f0e4145 (diff)
downloadrust-ac8169dc106f2005d41d969c114d85e8e53bce61.tar.gz
rust-ac8169dc106f2005d41d969c114d85e8e53bce61.zip
Rollup merge of #77093 - lcnr:const-generics-infer-warning, r=varkor
merge `need_type_info_err(_const)`

I hoped that this would automatically solve #76737 but it doesn't quite seem like it

fixes #77092

r? @varkor
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs277
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs5
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs18
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs37
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt.rs2
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs11
7 files changed, 223 insertions, 137 deletions
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 f87406c2ce4..2f3089f1a92 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
@@ -176,7 +176,10 @@ fn closure_return_type_suggestion(
         suggestion,
         Applicability::HasPlaceholders,
     );
-    err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
+    err.span_label(
+        span,
+        InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr),
+    );
 }
 
 /// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -217,65 +220,151 @@ impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
     }
 }
 
+/// Information about a constant or a type containing inference variables.
+pub struct InferenceDiagnosticsData {
+    pub name: String,
+    pub span: Option<Span>,
+    pub description: Cow<'static, str>,
+    pub parent_name: Option<String>,
+    pub parent_description: Option<&'static str>,
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    pub fn extract_type_name(
+    /// Extracts data used by diagnostic for either types or constants
+    /// which were stuck during inference.
+    pub fn extract_inference_diagnostics_data(
         &self,
-        ty: Ty<'tcx>,
+        arg: GenericArg<'tcx>,
         highlight: Option<ty::print::RegionHighlightMode>,
-    ) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
-        if 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(name, def_id) = var_origin.kind {
-                let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
-                let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id {
-                    let parent_name = self
-                        .tcx
-                        .def_key(parent_def_id)
-                        .disambiguated_data
-                        .data
-                        .get_opt_name()
-                        .map(|parent_symbol| parent_symbol.to_string());
-
-                    (parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)))
-                } else {
-                    (None, None)
-                };
+    ) -> InferenceDiagnosticsData {
+        match arg.unpack() {
+            GenericArgKind::Type(ty) => {
+                if 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(name, def_id) =
+                        var_origin.kind
+                    {
+                        let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
+                        let (parent_name, parent_description) =
+                            if let Some(parent_def_id) = parent_def_id {
+                                let parent_name = self
+                                    .tcx
+                                    .def_key(parent_def_id)
+                                    .disambiguated_data
+                                    .data
+                                    .get_opt_name()
+                                    .map(|parent_symbol| parent_symbol.to_string());
+
+                                (
+                                    parent_name,
+                                    Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
+                                )
+                            } else {
+                                (None, None)
+                            };
+
+                        if name != kw::SelfUpper {
+                            return InferenceDiagnosticsData {
+                                name: name.to_string(),
+                                span: Some(var_origin.span),
+                                description: "type parameter".into(),
+                                parent_name,
+                                parent_description,
+                            };
+                        }
+                    }
+                }
 
-                if name != kw::SelfUpper {
-                    return (
-                        name.to_string(),
-                        Some(var_origin.span),
-                        "type parameter".into(),
-                        parent_name,
-                        parent_desc,
-                    );
+                let mut s = String::new();
+                let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
+                if let Some(highlight) = highlight {
+                    printer.region_highlight_mode = highlight;
+                }
+                let _ = ty.print(printer);
+                InferenceDiagnosticsData {
+                    name: s,
+                    span: None,
+                    description: ty.prefix_string(),
+                    parent_name: None,
+                    parent_description: None,
                 }
             }
-        }
+            GenericArgKind::Const(ct) => {
+                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
+                    {
+                        let parent_def_id = self.tcx.parent(def_id);
+                        let (parent_name, parent_description) =
+                            if let Some(parent_def_id) = parent_def_id {
+                                let parent_name = self
+                                    .tcx
+                                    .def_key(parent_def_id)
+                                    .disambiguated_data
+                                    .data
+                                    .get_opt_name()
+                                    .map(|parent_symbol| parent_symbol.to_string());
+
+                                (
+                                    parent_name,
+                                    Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
+                                )
+                            } else {
+                                (None, None)
+                            };
+
+                        return InferenceDiagnosticsData {
+                            name: name.to_string(),
+                            span: Some(origin.span),
+                            description: "const parameter".into(),
+                            parent_name,
+                            parent_description,
+                        };
+                    }
 
-        let mut s = String::new();
-        let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
-        if let Some(highlight) = highlight {
-            printer.region_highlight_mode = highlight;
+                    debug_assert!(!origin.span.is_dummy());
+                    let mut s = String::new();
+                    let mut printer =
+                        ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
+                    if let Some(highlight) = highlight {
+                        printer.region_highlight_mode = highlight;
+                    }
+                    let _ = ct.print(printer);
+                    InferenceDiagnosticsData {
+                        name: s,
+                        span: Some(origin.span),
+                        description: "the constant".into(),
+                        parent_name: None,
+                        parent_description: None,
+                    }
+                } else {
+                    bug!("unexpect const: {:?}", ct);
+                }
+            }
+            GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
         }
-        let _ = ty.print(printer);
-        (s, None, ty.prefix_string(), None, None)
     }
 
-    // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well.
-    pub fn need_type_info_err(
+    pub fn emit_inference_failure_err(
         &self,
         body_id: Option<hir::BodyId>,
         span: Span,
-        ty: Ty<'tcx>,
+        arg: GenericArg<'tcx>,
         error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx> {
-        let ty = self.resolve_vars_if_possible(&ty);
-        let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
+        let arg = self.resolve_vars_if_possible(&arg);
+        let arg_data = self.extract_inference_diagnostics_data(arg, None);
+        let kind_str = match arg.unpack() {
+            GenericArgKind::Type(_) => "type",
+            GenericArgKind::Const(_) => "the value",
+            GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
+        };
 
-        let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
+        let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
         let ty_to_string = |ty: Ty<'tcx>| -> String {
             let mut s = String::new();
             let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
@@ -305,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
         let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
             pattern.span
-        } else if let Some(span) = name_sp {
+        } 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
@@ -352,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             _ => String::new(),
         };
 
-        // When `name` corresponds to a type argument, show the path of the full type we're
+        // 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
         // " in `std::result::Result<i32, E>`":
         // ```
@@ -391,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         &mut err,
                         &decl.output,
                         self.tcx.hir().body(body_id),
-                        &descr,
-                        &name,
+                        &arg_data.description,
+                        &arg_data.name,
                         &ret,
-                        parent_name,
-                        parent_descr,
+                        arg_data.parent_name,
+                        arg_data.parent_description,
                     );
                     // We don't want to give the other suggestions when the problem is the
                     // closure return type.
@@ -409,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 // 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) && name == "_" => {
+            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 type parameters specified", ty)
             }
-            Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
+            Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
                 let ty = ty_to_string(ty);
                 format!(
                     "the explicit type `{}`, where the type parameter `{}` is specified",
-                    ty, name,
+                    ty, arg_data.name,
                 )
             }
             _ => "a type".to_string(),
@@ -534,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         //   |               ^^^ cannot infer type for `S`
         //   |
         //   = note: type must be known at this point
-        let span = name_sp.unwrap_or(err_span);
+        let span = arg_data.span.unwrap_or(err_span);
         if !err
             .span
             .span_labels()
@@ -545,55 +634,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             // Avoid multiple labels pointing at `span`.
             err.span_label(
                 span,
-                InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr),
+                InferCtxt::cannot_infer_msg(
+                    kind_str,
+                    &arg_data.name,
+                    &arg_data.description,
+                    arg_data.parent_name,
+                    arg_data.parent_description,
+                ),
             );
         }
 
         err
     }
 
-    // FIXME(const_generics): We should either try and merge this with `need_type_info_err`
-    // or improve the errors created here.
-    //
-    // Unlike for type inference variables, we don't yet store the origin of const inference variables.
-    // This is needed for to get a more relevant error span.
-    pub fn need_type_info_err_const(
-        &self,
-        body_id: Option<hir::BodyId>,
-        span: Span,
-        ct: &'tcx ty::Const<'tcx>,
-        error_code: TypeAnnotationNeeded,
-    ) -> DiagnosticBuilder<'tcx> {
-        let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span);
-        if let Some(body_id) = body_id {
-            let expr = self.tcx.hir().expect_expr(body_id.hir_id);
-            local_visitor.visit_expr(expr);
-        }
-
-        let mut param_name = None;
-        let span = 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(param) = origin.kind {
-                param_name = Some(param);
-            }
-            origin.span
-        } else {
-            local_visitor.target_span
-        };
-
-        let error_code = error_code.into();
-        let mut err =
-            self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
-
-        if let Some(param_name) = param_name {
-            err.note(&format!("cannot infer the value of the const parameter `{}`", param_name));
-        } else {
-            err.note("unable to infer the value of a const parameter");
-        }
-
-        err
-    }
-
     /// 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(
@@ -647,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         ty: Ty<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
-        let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
+        let data = self.extract_inference_diagnostics_data(ty.into(), None);
 
         let mut err = struct_span_err!(
             self.tcx.sess,
@@ -656,18 +709,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             "type inside {} must be known in this context",
             kind,
         );
-        err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
+        err.span_label(
+            span,
+            InferCtxt::cannot_infer_msg(
+                "type",
+                &data.name,
+                &data.description,
+                data.parent_name,
+                data.parent_description,
+            ),
+        );
         err
     }
 
-    fn missing_type_msg(
+    fn cannot_infer_msg(
+        kind_str: &str,
         type_name: &str,
         descr: &str,
         parent_name: Option<String>,
         parent_descr: Option<&str>,
-    ) -> Cow<'static, str> {
+    ) -> String {
         if type_name == "_" {
-            "cannot infer type".into()
+            format!("cannot infer {}", kind_str)
         } else {
             let parent_desc = if let Some(parent_name) = parent_name {
                 let parent_type_descr = if let Some(parent_descr) = parent_descr {
@@ -681,7 +744,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 "".to_string()
             };
 
-            format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into()
+            // FIXME: We really shouldn't be dealing with strings here
+            // but instead use a sensible enum for cases like this.
+            let preposition = if "the value" == kind_str { "of" } else { "for" };
+            // For example: "cannot infer type for type parameter `T`"
+            format!(
+                "cannot infer {} {} {} `{}`{}",
+                kind_str, preposition, descr, type_name, parent_desc
+            )
+            .into()
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 2cbdc954e20..d7bfab8a7f8 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1163,7 +1163,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
             GenericParamDefKind::Const { .. } => {
                 let origin = ConstVariableOrigin {
-                    kind: ConstVariableOriginKind::ConstParameterDefinition(param.name),
+                    kind: ConstVariableOriginKind::ConstParameterDefinition(
+                        param.name,
+                        param.def_id,
+                    ),
                     span,
                 };
                 let const_var_id =
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index a60a17befef..4d884dde393 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -4,8 +4,9 @@ use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify::{
     self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue,
 };
+use rustc_span::def_id::DefId;
 use rustc_span::symbol::Symbol;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 
 use std::cmp;
 use std::marker::PhantomData;
@@ -124,8 +125,7 @@ pub struct ConstVariableOrigin {
 pub enum ConstVariableOriginKind {
     MiscVariable,
     ConstInference,
-    // FIXME(const_generics): Consider storing the `DefId` of the param here.
-    ConstParameterDefinition(Symbol),
+    ConstParameterDefinition(Symbol, DefId),
     SubstitutionPlaceholder,
 }
 
@@ -176,17 +176,17 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
     type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
 
     fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
-        let val = match (value1.val, value2.val) {
+        let (val, span) = match (value1.val, value2.val) {
             (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
                 bug!("equating two const variables, both of which have known values")
             }
 
             // If one side is known, prefer that one.
             (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
-                Ok(value1.val)
+                (value1.val, value1.origin.span)
             }
             (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
-                Ok(value2.val)
+                (value2.val, value2.origin.span)
             }
 
             // If both sides are *unknown*, it hardly matters, does it?
@@ -200,14 +200,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
                 // universe is the minimum of the two universes, because that is
                 // the one which contains the fewest names in scope.
                 let universe = cmp::min(universe1, universe2);
-                Ok(ConstVariableValue::Unknown { universe })
+                (ConstVariableValue::Unknown { universe }, value1.origin.span)
             }
-        }?;
+        };
 
         Ok(ConstVarValue {
             origin: ConstVariableOrigin {
                 kind: ConstVariableOriginKind::ConstInference,
-                span: DUMMY_SP,
+                span: span,
             },
             val,
         })
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
index da7bc1564c0..5f64eb3dba8 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
@@ -396,7 +396,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     ) -> Option<RegionNameHighlight> {
         let mut highlight = RegionHighlightMode::default();
         highlight.highlighting_region_vid(needle_fr, counter);
-        let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0;
+        let type_name =
+            self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
 
         debug!(
             "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
@@ -404,7 +405,6 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         );
         if type_name.find(&format!("'{}", counter)).is_some() {
             // Only add a label if we can confirm that a region was labelled.
-
             Some(RegionNameHighlight::CannotMatchHirTy(span, type_name))
         } else {
             None
@@ -646,7 +646,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
 
         let mut highlight = RegionHighlightMode::default();
         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
-        let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0;
+        let type_name =
+            self.infcx.extract_inference_diagnostics_data(return_ty.into(), Some(highlight)).name;
 
         let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
 
@@ -698,7 +699,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
 
         let mut highlight = RegionHighlightMode::default();
         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
-        let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0;
+        let type_name =
+            self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
 
         let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index bda4351b2f2..1b234a1535c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -20,7 +20,6 @@ use rustc_hir::Node;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{
     self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
     TypeFoldable, WithConstness,
@@ -1513,10 +1512,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
                 if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
-                    self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
+                    self.emit_inference_failure_err(
+                        body_id,
+                        span,
+                        self_ty.into(),
+                        ErrorCode::E0282,
+                    )
+                    .emit();
                     return;
                 }
-                let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283);
+                let mut err = self.emit_inference_failure_err(
+                    body_id,
+                    span,
+                    self_ty.into(),
+                    ErrorCode::E0283,
+                );
                 err.note(&format!("cannot satisfy `{}`", predicate));
                 if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
                     self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
@@ -1580,17 +1590,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                     return;
                 }
 
-                match arg.unpack() {
-                    GenericArgKind::Lifetime(lt) => {
-                        span_bug!(span, "unexpected well formed predicate: {:?}", lt)
-                    }
-                    GenericArgKind::Type(ty) => {
-                        self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
-                    }
-                    GenericArgKind::Const(ct) => {
-                        self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282)
-                    }
-                }
+                self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282)
             }
 
             ty::PredicateAtom::Subtype(data) => {
@@ -1601,7 +1601,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 let SubtypePredicate { a_is_expected: _, a, b } = data;
                 // both must be type variables, or the other would've been instantiated
                 assert!(a.is_ty_var() && b.is_ty_var());
-                self.need_type_info_err(body_id, span, a, ErrorCode::E0282)
+                self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282)
             }
             ty::PredicateAtom::Projection(data) => {
                 let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx);
@@ -1612,7 +1612,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 }
                 if self_ty.needs_infer() && ty.needs_infer() {
                     // We do this for the `foo.collect()?` case to produce a suggestion.
-                    let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284);
+                    let mut err = self.emit_inference_failure_err(
+                        body_id,
+                        span,
+                        self_ty.into(),
+                        ErrorCode::E0284,
+                    );
                     err.note(&format!("cannot satisfy `{}`", predicate));
                     err
                 } else {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs
index a03b8064b59..79d6c7dbfda 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs
@@ -2991,7 +2991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.need_type_info_err((**self).body_id, sp, ty, E0282)
+                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
                     .note("type must be known at this point")
                     .emit();
             }
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index b55f62ee436..6fd7277a1c3 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -653,7 +653,12 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
     fn report_type_error(&self, t: Ty<'tcx>) {
         if !self.tcx.sess.has_errors() {
             self.infcx
-                .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282)
+                .emit_inference_failure_err(
+                    Some(self.body.id()),
+                    self.span.to_span(self.tcx),
+                    t.into(),
+                    E0282,
+                )
                 .emit();
         }
     }
@@ -661,10 +666,10 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
     fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) {
         if !self.tcx.sess.has_errors() {
             self.infcx
-                .need_type_info_err_const(
+                .emit_inference_failure_err(
                     Some(self.body.id()),
                     self.span.to_span(self.tcx),
-                    c,
+                    c.into(),
                     E0282,
                 )
                 .emit();