]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_typeck/src/check/method/suggest.rs
fix: wrong trait import suggestion for T:
[rust.git] / compiler / rustc_typeck / src / check / method / suggest.rs
index e1d6b5d2bd425672b7a07ded2a29a4a2cc09b14e..e6560ca4d9b90e7827e30827220cb075ade931cc 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -17,7 +18,7 @@
 use rustc_middle::ty::ToPolyTraitRef;
 use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, MultiSpan, Span};
+use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
 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::{
@@ -110,7 +111,7 @@ pub fn report_method_error(
 
             for (idx, source) in sources.iter().take(limit).enumerate() {
                 match *source {
-                    CandidateSource::ImplSource(impl_did) => {
+                    CandidateSource::Impl(impl_did) => {
                         // Provide the best span we can. Use the item, if local to crate, else
                         // the impl, if local to crate (item may be defaulted), else nothing.
                         let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
@@ -193,7 +194,7 @@ pub fn report_method_error(
                             );
                         }
                     }
-                    CandidateSource::TraitSource(trait_did) => {
+                    CandidateSource::Trait(trait_did) => {
                         let Some(item) = self.associated_value(trait_did, item_name) else { continue };
                         let item_span = self
                             .tcx
@@ -270,7 +271,7 @@ pub fn report_method_error(
                         (None, true) => "variant",
                     }
                 };
-                // FIXME(eddyb) this intendation is probably unnecessary.
+                // FIXME(eddyb) this indentation is probably unnecessary.
                 let mut err = {
                     // Suggest clamping down the type if the method that is being attempted to
                     // be used exists at all, and the type is an ambiguous numeric type
@@ -279,7 +280,7 @@ pub fn report_method_error(
                         .into_iter()
                         .filter_map(|info| self.associated_value(info.def_id, item_name));
                     // There are methods that are defined on the primitive types and won't be
-                    // found when exploring `all_traits`, but we also need them to be acurate on
+                    // found when exploring `all_traits`, but we also need them to be accurate on
                     // our suggestions (#47759).
                     let found_assoc = |ty: Ty<'tcx>| {
                         simplify_type(tcx, ty, TreatParams::AsPlaceholders)
@@ -515,23 +516,22 @@ fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                     custom_span_label = true;
                 }
                 if static_sources.len() == 1 {
-                    let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
-                        static_sources.get(0)
-                    {
-                        // When the "method" is resolved through dereferencing, we really want the
-                        // original type that has the associated function for accurate suggestions.
-                        // (#61411)
-                        let ty = tcx.at(span).type_of(*impl_did);
-                        match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
-                            (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
-                                // Use `actual` as it will have more `substs` filled in.
-                                self.ty_to_value_string(actual.peel_refs())
+                    let ty_str =
+                        if let Some(CandidateSource::Impl(impl_did)) = static_sources.get(0) {
+                            // When the "method" is resolved through dereferencing, we really want the
+                            // original type that has the associated function for accurate suggestions.
+                            // (#61411)
+                            let ty = tcx.at(span).type_of(*impl_did);
+                            match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
+                                (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
+                                    // Use `actual` as it will have more `substs` filled in.
+                                    self.ty_to_value_string(actual.peel_refs())
+                                }
+                                _ => self.ty_to_value_string(ty.peel_refs()),
                             }
-                            _ => self.ty_to_value_string(ty.peel_refs()),
-                        }
-                    } else {
-                        self.ty_to_value_string(actual.peel_refs())
-                    };
+                        } else {
+                            self.ty_to_value_string(actual.peel_refs())
+                        };
                     if let SelfSource::MethodCall(expr) = source {
                         err.span_suggestion(
                             expr.span.to(span),
@@ -1880,9 +1880,15 @@ fn suggest_traits_to_import(
                                 };
                             let sp = hir.span(id);
                             let sp = if let Some(first_bound) = has_bounds {
-                                // `sp` only covers `T`, change it so that it covers
-                                // `T:` when appropriate
                                 sp.until(first_bound.span())
+                            } else if let Some(colon_sp) =
+                                // If the generic param is declared with a colon but without bounds:
+                                // fn foo<T:>(t: T) { ... }
+                                param.colon_span_for_suggestions(
+                                    self.inh.tcx.sess.source_map(),
+                                )
+                            {
+                                sp.to(colon_sp)
                             } else {
                                 sp
                             };