about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-03-10 12:20:53 +0100
committerGitHub <noreply@github.com>2022-03-10 12:20:53 +0100
commite7281d08de338fc091ce12f90b48d7b4de50a138 (patch)
tree427236d504552c056fe8da6445f17ed7c50de96c
parentfe034cb43baf6fe415ca0f530cd72614df447b70 (diff)
parent32d7f8145a33d7b3061cf29dd997fd8c5d2117b6 (diff)
downloadrust-e7281d08de338fc091ce12f90b48d7b4de50a138.tar.gz
rust-e7281d08de338fc091ce12f90b48d7b4de50a138.zip
Rollup merge of #94746 - notriddle:notriddle/method-rustc-on-unimplemented, r=davidtwco
diagnostics: use rustc_on_unimplemented to recommend `[].iter()`

To make this work, the `#[rustc_on_unimplemented]` data needs to be used to
report method resolution errors, which is most of what this commit does.

Fixes #94581
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs6
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs362
-rw-r--r--library/core/src/iter/traits/iterator.rs5
-rw-r--r--src/test/ui/issues/issue-21596.stderr4
-rw-r--r--src/test/ui/methods/issues/issue-94581.rs7
-rw-r--r--src/test/ui/methods/issues/issue-94581.stderr15
-rw-r--r--src/test/ui/methods/method-call-err-msg.rs2
-rw-r--r--src/test/ui/methods/method-call-err-msg.stderr4
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.rs2
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr4
11 files changed, 258 insertions, 162 deletions
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 8b0e7794f92..da54ad06e04 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1887,6 +1887,15 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    pub fn is_array_slice(self) -> bool {
+        match self.kind() {
+            Slice(_) => true,
+            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
+            _ => false,
+        }
+    }
+
+    #[inline]
     pub fn is_array(self) -> bool {
         matches!(self.kind(), Array(..))
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 6dfbdace8e2..59c88b6603c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -11,7 +11,7 @@ use std::iter;
 
 use super::InferCtxtPrivExt;
 
-crate trait InferCtxtExt<'tcx> {
+pub trait InferCtxtExt<'tcx> {
     /*private*/
     fn impl_similar_to(
         &self,
@@ -204,6 +204,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 flags.push((sym::_Self, Some("{integral}".to_owned())));
             }
 
+            if self_ty.is_array_slice() {
+                flags.push((sym::_Self, Some("&[]".to_owned())));
+            }
+
             if let ty::Array(aty, len) = self_ty.kind() {
                 flags.push((sym::_Self, Some("[]".to_owned())));
                 flags.push((sym::_Self, Some(format!("[{}]", aty))));
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 0ae2dfa180b..504e1ce8c9f 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -19,9 +19,10 @@ use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, MultiSpan, Span};
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
+    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
 };
 
 use std::cmp::Ordering;
@@ -483,150 +484,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
-                let mut label_span_not_found = || {
-                    if unsatisfied_predicates.is_empty() {
-                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
-                        let is_string_or_ref_str = match actual.kind() {
-                            ty::Ref(_, ty, _) => {
-                                ty.is_str()
-                                    || matches!(
-                                        ty.kind(),
-                                        ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
-                                    )
-                            }
-                            ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
-                            _ => false,
-                        };
-                        if is_string_or_ref_str && item_name.name == sym::iter {
-                            err.span_suggestion_verbose(
-                                item_name.span,
-                                "because of the in-memory representation of `&str`, to obtain \
-                                 an `Iterator` over each of its codepoint use method `chars`",
-                                String::from("chars"),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
-                            let mut inherent_impls_candidate = self
-                                .tcx
-                                .inherent_impls(adt.did)
-                                .iter()
-                                .copied()
-                                .filter(|def_id| {
-                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
-                                        // Check for both mode is the same so we avoid suggesting
-                                        // incorrect associated item.
-                                        match (mode, assoc.fn_has_self_parameter, source) {
-                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
-                                                // We check that the suggest type is actually
-                                                // different from the received one
-                                                // So we avoid suggestion method with Box<Self>
-                                                // for instance
-                                                self.tcx.at(span).type_of(*def_id) != actual
-                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
-                                            }
-                                            (Mode::Path, false, _) => true,
-                                            _ => false,
-                                        }
-                                    } else {
-                                        false
-                                    }
-                                })
-                                .collect::<Vec<_>>();
-                            if !inherent_impls_candidate.is_empty() {
-                                inherent_impls_candidate.sort();
-                                inherent_impls_candidate.dedup();
-
-                                // number of type to shows at most.
-                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
-                                let type_candidates = inherent_impls_candidate
-                                    .iter()
-                                    .take(limit)
-                                    .map(|impl_item| {
-                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
-                                    })
-                                    .collect::<Vec<_>>()
-                                    .join("\n");
-                                let additional_types = if inherent_impls_candidate.len() > limit {
-                                    format!(
-                                        "\nand {} more types",
-                                        inherent_impls_candidate.len() - limit
-                                    )
-                                } else {
-                                    "".to_string()
-                                };
-                                err.note(&format!(
-                                    "the {item_kind} was found for\n{}{}",
-                                    type_candidates, additional_types
-                                ));
-                            }
-                        }
-                    } else {
-                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
-                    }
-                };
-
-                // If the method name is the name of a field with a function or closure type,
-                // give a helping note that it has to be called as `(x.f)(...)`.
-                if let SelfSource::MethodCall(expr) = source {
-                    let field_receiver =
-                        self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
-                            ty::Adt(def, substs) if !def.is_enum() => {
-                                let variant = &def.non_enum_variant();
-                                self.tcx.find_field_index(item_name, variant).map(|index| {
-                                    let field = &variant.fields[index];
-                                    let field_ty = field.ty(tcx, substs);
-                                    (field, field_ty)
-                                })
-                            }
-                            _ => None,
-                        });
-
-                    if let Some((field, field_ty)) = field_receiver {
-                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
-                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
-
-                        if is_accessible {
-                            if self.is_fn_ty(field_ty, span) {
-                                let expr_span = expr.span.to(item_name.span);
-                                err.multipart_suggestion(
-                                    &format!(
-                                        "to call the function stored in `{}`, \
-                                         surround the field access with parentheses",
-                                        item_name,
-                                    ),
-                                    vec![
-                                        (expr_span.shrink_to_lo(), '('.to_string()),
-                                        (expr_span.shrink_to_hi(), ')'.to_string()),
-                                    ],
-                                    Applicability::MachineApplicable,
-                                );
-                            } else {
-                                let call_expr = self
-                                    .tcx
-                                    .hir()
-                                    .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-
-                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
-                                    err.span_suggestion(
-                                        span,
-                                        "remove the arguments",
-                                        String::new(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            }
-                        }
-
-                        let field_kind = if is_accessible { "field" } else { "private field" };
-                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
-                    } else if lev_candidate.is_none() && static_sources.is_empty() {
-                        label_span_not_found();
-                    }
-                } else {
-                    label_span_not_found();
-                }
-
                 if self.is_fn_ty(rcvr_ty, span) {
                     fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                         err.note(
@@ -645,12 +502,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
+                let mut custom_span_label = false;
+
                 if !static_sources.is_empty() {
                     err.note(
                         "found the following associated functions; to be used as methods, \
                          functions must have a `self` parameter",
                     );
                     err.span_label(span, "this is an associated function, not a method");
+                    custom_span_label = true;
                 }
                 if static_sources.len() == 1 {
                     let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
@@ -686,6 +546,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     report_candidates(span, &mut err, static_sources, sugg_span);
                 }
 
+                let mut bound_spans = vec![];
                 let mut restrict_type_params = false;
                 let mut unsatisfied_bounds = false;
                 if item_name.name == sym::count && self.is_slice_ty(actual, span) {
@@ -709,7 +570,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
                     };
                     let mut type_params = FxHashMap::default();
-                    let mut bound_spans = vec![];
+
+                    // Pick out the list of unimplemented traits on the receiver.
+                    // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+                    let mut unimplemented_traits = FxHashMap::default();
+                    for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
+                        if let (ty::PredicateKind::Trait(p), Some(cause)) =
+                            (predicate.kind().skip_binder(), cause.as_ref())
+                        {
+                            if p.trait_ref.self_ty() != rcvr_ty {
+                                // This is necessary, not just to keep the errors clean, but also
+                                // because our derived obligations can wind up with a trait ref that
+                                // requires a different param_env to be correctly compared.
+                                continue;
+                            }
+                            unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+                                predicate.kind().rebind(p.trait_ref),
+                                Obligation {
+                                    cause: cause.clone(),
+                                    param_env: self.param_env,
+                                    predicate: predicate.clone(),
+                                    recursion_depth: 0,
+                                },
+                            ));
+                        }
+                    }
 
                     let mut collect_type_param_suggestions =
                         |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
@@ -945,11 +830,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
                     bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
                     bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
-                    bound_spans.sort();
-                    bound_spans.dedup();
-                    for (span, msg) in bound_spans.into_iter() {
-                        err.span_label(span, &msg);
-                    }
+
                     if !bound_list.is_empty() || !skip_list.is_empty() {
                         let bound_list = bound_list
                             .into_iter()
@@ -957,9 +838,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .collect::<Vec<_>>()
                             .join("\n");
                         let actual_prefix = actual.prefix_string(self.tcx);
-                        err.set_primary_message(&format!(
+                        info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+                        let (primary_message, label) = if unimplemented_traits.len() == 1 {
+                            unimplemented_traits
+                                .into_iter()
+                                .next()
+                                .map(|(_, (trait_ref, obligation))| {
+                                    if trait_ref.self_ty().references_error()
+                                        || actual.references_error()
+                                    {
+                                        // Avoid crashing.
+                                        return (None, None);
+                                    }
+                                    let OnUnimplementedNote { message, label, .. } =
+                                        self.infcx.on_unimplemented_note(trait_ref, &obligation);
+                                    (message, label)
+                                })
+                                .unwrap_or((None, None))
+                        } else {
+                            (None, None)
+                        };
+                        let primary_message = primary_message.unwrap_or_else(|| format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
+                        err.set_primary_message(&primary_message);
+                        if let Some(label) = label {
+                            custom_span_label = true;
+                            err.span_label(span, label);
+                        }
                         if !bound_list.is_empty() {
                             err.note(&format!(
                                 "the following trait bounds were not satisfied:\n{bound_list}"
@@ -971,6 +877,156 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
+                let mut label_span_not_found = || {
+                    if unsatisfied_predicates.is_empty() {
+                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                        let is_string_or_ref_str = match actual.kind() {
+                            ty::Ref(_, ty, _) => {
+                                ty.is_str()
+                                    || matches!(
+                                        ty.kind(),
+                                        ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
+                                    )
+                            }
+                            ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
+                            _ => false,
+                        };
+                        if is_string_or_ref_str && item_name.name == sym::iter {
+                            err.span_suggestion_verbose(
+                                item_name.span,
+                                "because of the in-memory representation of `&str`, to obtain \
+                                 an `Iterator` over each of its codepoint use method `chars`",
+                                String::from("chars"),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
+                            let mut inherent_impls_candidate = self
+                                .tcx
+                                .inherent_impls(adt.did)
+                                .iter()
+                                .copied()
+                                .filter(|def_id| {
+                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
+                                        // Check for both mode is the same so we avoid suggesting
+                                        // incorrect associated item.
+                                        match (mode, assoc.fn_has_self_parameter, source) {
+                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                                // We check that the suggest type is actually
+                                                // different from the received one
+                                                // So we avoid suggestion method with Box<Self>
+                                                // for instance
+                                                self.tcx.at(span).type_of(*def_id) != actual
+                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            }
+                                            (Mode::Path, false, _) => true,
+                                            _ => false,
+                                        }
+                                    } else {
+                                        false
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            if !inherent_impls_candidate.is_empty() {
+                                inherent_impls_candidate.sort();
+                                inherent_impls_candidate.dedup();
+
+                                // number of type to shows at most.
+                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                                let type_candidates = inherent_impls_candidate
+                                    .iter()
+                                    .take(limit)
+                                    .map(|impl_item| {
+                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                                    })
+                                    .collect::<Vec<_>>()
+                                    .join("\n");
+                                let additional_types = if inherent_impls_candidate.len() > limit {
+                                    format!(
+                                        "\nand {} more types",
+                                        inherent_impls_candidate.len() - limit
+                                    )
+                                } else {
+                                    "".to_string()
+                                };
+                                err.note(&format!(
+                                    "the {item_kind} was found for\n{}{}",
+                                    type_candidates, additional_types
+                                ));
+                            }
+                        }
+                    } else {
+                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+                    }
+                };
+
+                // If the method name is the name of a field with a function or closure type,
+                // give a helping note that it has to be called as `(x.f)(...)`.
+                if let SelfSource::MethodCall(expr) = source {
+                    let field_receiver =
+                        self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
+                            ty::Adt(def, substs) if !def.is_enum() => {
+                                let variant = &def.non_enum_variant();
+                                self.tcx.find_field_index(item_name, variant).map(|index| {
+                                    let field = &variant.fields[index];
+                                    let field_ty = field.ty(tcx, substs);
+                                    (field, field_ty)
+                                })
+                            }
+                            _ => None,
+                        });
+
+                    if let Some((field, field_ty)) = field_receiver {
+                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
+                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
+
+                        if is_accessible {
+                            if self.is_fn_ty(field_ty, span) {
+                                let expr_span = expr.span.to(item_name.span);
+                                err.multipart_suggestion(
+                                    &format!(
+                                        "to call the function stored in `{}`, \
+                                         surround the field access with parentheses",
+                                        item_name,
+                                    ),
+                                    vec![
+                                        (expr_span.shrink_to_lo(), '('.to_string()),
+                                        (expr_span.shrink_to_hi(), ')'.to_string()),
+                                    ],
+                                    Applicability::MachineApplicable,
+                                );
+                            } else {
+                                let call_expr = self
+                                    .tcx
+                                    .hir()
+                                    .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+
+                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
+                                    err.span_suggestion(
+                                        span,
+                                        "remove the arguments",
+                                        String::new(),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
+                            }
+                        }
+
+                        let field_kind = if is_accessible { "field" } else { "private field" };
+                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
+                    } else if lev_candidate.is_none() && !custom_span_label {
+                        label_span_not_found();
+                    }
+                } else if !custom_span_label {
+                    label_span_not_found();
+                }
+
+                bound_spans.sort();
+                bound_spans.dedup();
+                for (span, msg) in bound_spans.into_iter() {
+                    err.span_label(span, &msg);
+                }
+
                 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
                 } else {
                     self.suggest_traits_to_import(
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index b38df1c2d02..c35d0784dd5 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -35,6 +35,11 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
               to have a bounded `RangeInclusive`: `0..=end`"
     ),
     on(
+        _Self = "[]",
+        label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
+    ),
+    on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
+    on(
         _Self = "&str",
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr
index b0524f056ef..a336d1b0ed5 100644
--- a/src/test/ui/issues/issue-21596.stderr
+++ b/src/test/ui/issues/issue-21596.stderr
@@ -1,8 +1,8 @@
-error[E0599]: the method `to_string` exists for raw pointer `*const u8`, but its trait bounds were not satisfied
+error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
   --> $DIR/issue-21596.rs:4:22
    |
 LL |     println!("{}", z.to_string());
-   |                      ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds
+   |                      ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
    |
    = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
    = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
diff --git a/src/test/ui/methods/issues/issue-94581.rs b/src/test/ui/methods/issues/issue-94581.rs
new file mode 100644
index 00000000000..df393e91db0
--- /dev/null
+++ b/src/test/ui/methods/issues/issue-94581.rs
@@ -0,0 +1,7 @@
+fn get_slice() -> &'static [i32] {
+    &[1, 2, 3, 4]
+}
+
+fn main() {
+    let sqsum = get_slice().map(|i| i * i).sum(); //~ ERROR [E0599]
+}
diff --git a/src/test/ui/methods/issues/issue-94581.stderr b/src/test/ui/methods/issues/issue-94581.stderr
new file mode 100644
index 00000000000..d6be29cf582
--- /dev/null
+++ b/src/test/ui/methods/issues/issue-94581.stderr
@@ -0,0 +1,15 @@
+error[E0599]: `&'static [i32]` is not an iterator
+  --> $DIR/issue-94581.rs:6:29
+   |
+LL |     let sqsum = get_slice().map(|i| i * i).sum();
+   |                             ^^^ `&'static [i32]` is not an iterator; try calling `.iter()`
+   |
+   = note: the following trait bounds were not satisfied:
+           `&'static [i32]: Iterator`
+           which is required by `&mut &'static [i32]: Iterator`
+           `[i32]: Iterator`
+           which is required by `&mut [i32]: Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/methods/method-call-err-msg.rs b/src/test/ui/methods/method-call-err-msg.rs
index 86d00ca3760..d53ef445afc 100644
--- a/src/test/ui/methods/method-call-err-msg.rs
+++ b/src/test/ui/methods/method-call-err-msg.rs
@@ -16,7 +16,7 @@ fn main() {
 
     let y = Foo;
     y.zero()
-     .take()    //~ ERROR the method
+     .take()    //~ ERROR not an iterator
      .one(0);
     y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied
 }
diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr
index c1183e053eb..c410e076dde 100644
--- a/src/test/ui/methods/method-call-err-msg.stderr
+++ b/src/test/ui/methods/method-call-err-msg.stderr
@@ -40,7 +40,7 @@ note: associated function defined here
 LL |     fn two(self, _: isize, _: isize) -> Foo { self }
    |        ^^^ ----  --------  --------
 
-error[E0599]: the method `take` exists for struct `Foo`, but its trait bounds were not satisfied
+error[E0599]: `Foo` is not an iterator
   --> $DIR/method-call-err-msg.rs:19:7
    |
 LL | pub struct Foo;
@@ -50,7 +50,7 @@ LL | pub struct Foo;
    | doesn't satisfy `Foo: Iterator`
 ...
 LL |      .take()
-   |       ^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds
+   |       ^^^^ `Foo` is not an iterator
    |
    = note: the following trait bounds were not satisfied:
            `Foo: Iterator`
diff --git a/src/test/ui/mismatched_types/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs
index 17d2292baaf..0252ba2eb04 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.rs
+++ b/src/test/ui/mismatched_types/issue-36053-2.rs
@@ -5,6 +5,6 @@
 use std::iter::once;
 fn main() {
     once::<&str>("str").fuse().filter(|a: &str| true).count();
-    //~^ ERROR the method
+    //~^ ERROR not an iterator
     //~| ERROR type mismatch in closure arguments
 }
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index a8bcdf5efe9..b1010171eb2 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -12,11 +12,11 @@ note: required by a bound in `filter`
 LL |         P: FnMut(&Self::Item) -> bool,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `filter`
 
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>`, but its trait bounds were not satisfied
+error[E0599]: `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
   --> $DIR/issue-36053-2.rs:7:55
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                       --------------  ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` due to unsatisfied trait bounds
+   |                                       --------------  ^^^^^ `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
    |                                       |
    |                                       doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
    |                                       doesn't satisfy `_: FnMut<(&&str,)>`