]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_typeck/src/check/method/suggest.rs
Auto merge of #79608 - alessandrod:bpf, r=nagisa
[rust.git] / compiler / rustc_typeck / src / check / method / suggest.rs
index 2320a29e6d823a8c362fcd82638c0b4ae3a5c482..16382c7e7a4bdce9ce540166f8416057facbc5ef 100644 (file)
@@ -383,6 +383,42 @@ pub fn report_method_error(
                         return None;
                     } else {
                         span = item_name.span;
+
+                        // Don't show generic arguments when the method can't be found in any implementation (#81576).
+                        let mut ty_str_reported = ty_str.clone();
+                        if let ty::Adt(_, ref generics) = actual.kind() {
+                            if generics.len() > 0 {
+                                let mut autoderef = self.autoderef(span, actual);
+                                let candidate_found = autoderef.any(|(ty, _)| {
+                                    if let ty::Adt(ref adt_deref, _) = ty.kind() {
+                                        self.tcx
+                                            .inherent_impls(adt_deref.did)
+                                            .iter()
+                                            .filter_map(|def_id| {
+                                                self.associated_item(
+                                                    *def_id,
+                                                    item_name,
+                                                    Namespace::ValueNS,
+                                                )
+                                            })
+                                            .count()
+                                            >= 1
+                                    } else {
+                                        false
+                                    }
+                                });
+                                let has_deref = autoderef.step_count() > 0;
+                                if !candidate_found
+                                    && !has_deref
+                                    && unsatisfied_predicates.is_empty()
+                                {
+                                    if let Some((path_string, _)) = ty_str.split_once('<') {
+                                        ty_str_reported = path_string.to_string();
+                                    }
+                                }
+                            }
+                        }
+
                         let mut err = struct_span_err!(
                             tcx.sess,
                             span,
@@ -391,7 +427,7 @@ pub fn report_method_error(
                             item_kind,
                             item_name,
                             actual.prefix_string(self.tcx),
-                            ty_str,
+                            ty_str_reported,
                         );
                         if let Mode::MethodCall = mode {
                             if let SelfSource::MethodCall(call) = source {
@@ -449,6 +485,63 @@ pub fn report_method_error(
                 let mut label_span_not_found = || {
                     if unsatisfied_predicates.is_empty() {
                         err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                        if let ty::Adt(ref 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_item(*def_id, item_name, Namespace::ValueNS)
+                                    {
+                                        // 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.len() > 0 {
+                                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"));
                     }