about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src/traits
diff options
context:
space:
mode:
authorEsteban Kuber <esteban@kuber.com.ar>2022-03-27 01:49:01 +0000
committerEsteban Kuber <esteban@kuber.com.ar>2022-04-04 21:06:35 +0000
commitef91519b45d2bbf0ce8c0180118160562eaaa0ca (patch)
treeab798e750270dc35abaadabf38e6946025faf9b8 /compiler/rustc_trait_selection/src/traits
parente2bba0708a1e4b0c21f94de56c2bd5d66d3b825f (diff)
Dedup logic and improve output for other types that impl trait
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs121
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs7
2 files changed, 65 insertions, 63 deletions
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 fdafb2d3d41..09b445058c0 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -30,7 +30,7 @@ use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
-    self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
@@ -1756,6 +1756,60 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         trait_ref: ty::PolyTraitRef<'tcx>,
         err: &mut Diagnostic,
     ) -> bool {
+        let report = |mut candidates: Vec<TraitRef<'_>>, err: &mut Diagnostic| {
+            candidates.sort();
+            candidates.dedup();
+            let len = candidates.len();
+            if candidates.len() == 0 {
+                return false;
+            }
+            let trait_ref = candidates[0];
+            if candidates.len() == 1 {
+                err.highlighted_help(vec![
+                    (
+                        format!(
+                            "the trait `{}` is implemented for `",
+                            trait_ref.print_only_trait_path()
+                        ),
+                        Style::NoStyle,
+                    ),
+                    (candidates[0].self_ty().to_string(), Style::Highlight),
+                    ("`".to_string(), Style::NoStyle),
+                ]);
+                return true;
+            }
+            // Check if the trait is the same in all cases. If so, we'll only show the type.
+            // FIXME: there *has* to be a better way!
+            let mut traits: Vec<_> = candidates
+                .iter()
+                .map(|c| format!("{}", c).split(" as ").last().unwrap().to_string())
+                .collect();
+            traits.sort();
+            traits.dedup();
+
+            let mut candidates: Vec<String> = candidates
+                .into_iter()
+                .map(|c| {
+                    if traits.len() == 1 {
+                        format!("\n  {}", c.self_ty())
+                    } else {
+                        format!("\n  {}", c)
+                    }
+                })
+                .collect();
+
+            candidates.sort();
+            candidates.dedup();
+            let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
+            err.help(&format!(
+                "the following other types implement trait `{}`:{}{}",
+                trait_ref.print_only_trait_path(),
+                candidates[..end].join(""),
+                if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
+            ));
+            true
+        };
+
         let def_id = trait_ref.def_id();
         if impl_candidates.is_empty() {
             if self.tcx.trait_is_auto(def_id)
@@ -1765,7 +1819,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                 // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
                 return false;
             }
-            let mut normalized_impl_candidates: Vec<_> = self
+            let normalized_impl_candidates: Vec<_> = self
                 .tcx
                 .all_impls(def_id)
                 // Ignore automatically derived impls and `!Trait` impls.
@@ -1776,45 +1830,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                 .filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
                 // Avoid mentioning type parameters.
                 .filter(|trait_ref| !matches!(trait_ref.self_ty().kind(), ty::Param(_)))
-                .map(|trait_ref| format!("\n  {}", trait_ref.self_ty()))
                 .collect();
-            normalized_impl_candidates.sort();
-            normalized_impl_candidates.dedup();
-            let len = normalized_impl_candidates.len();
-            if len == 0 {
-                return false;
-            }
-            if len == 1 {
-                err.highlighted_help(vec![
-                    (
-                        format!(
-                            "the trait `{}` is implemented for `",
-                            trait_ref.print_only_trait_path()
-                        ),
-                        Style::NoStyle,
-                    ),
-                    (normalized_impl_candidates[0].trim().to_string(), Style::Highlight),
-                    ("`".to_string(), Style::NoStyle),
-                ]);
-                return true;
-            }
-            let end = if normalized_impl_candidates.len() <= 9 {
-                normalized_impl_candidates.len()
-            } else {
-                8
-            };
-            err.help(&format!(
-                "the following other types implement trait `{}`:{}{}",
-                trait_ref.print_only_trait_path(),
-                normalized_impl_candidates[..end].join(""),
-                if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
-            ));
-            return true;
+            return report(normalized_impl_candidates, err);
         }
 
-        let len = impl_candidates.len();
-        let end = if impl_candidates.len() <= 9 { impl_candidates.len() } else { 8 };
-
         let normalize = |candidate| {
             self.tcx.infer_ctxt().enter(|ref infcx| {
                 let normalized = infcx
@@ -1822,8 +1841,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                     .normalize(candidate)
                     .ok();
                 match normalized {
-                    Some(normalized) => format!("\n  {}", normalized.value),
-                    None => format!("\n  {}", candidate),
+                    Some(normalized) => normalized.value,
+                    None => candidate,
                 }
             })
         };
@@ -1834,7 +1853,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         //
         // Prefer more similar candidates first, then sort lexicographically
         // by their normalized string representation.
-        let first_candidate = impl_candidates.get(0).map(|candidate| candidate.trait_ref);
         let mut normalized_impl_candidates_and_similarities = impl_candidates
             .into_iter()
             .map(|ImplCandidate { trait_ref, similarity }| {
@@ -1850,26 +1868,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
             .map(|(_, normalized)| normalized)
             .collect::<Vec<_>>();
 
-        if normalized_impl_candidates.len() == 1 {
-            err.highlighted_help(vec![
-                (
-                    format!(
-                        "the trait `{}` is implemented for `",
-                        first_candidate.unwrap().print_only_trait_path()
-                    ),
-                    Style::NoStyle,
-                ),
-                (first_candidate.unwrap().self_ty().to_string(), Style::Highlight),
-                ("`".to_string(), Style::NoStyle),
-            ]);
-        } else {
-            err.help(&format!(
-                "the following implementations were found:{}{}",
-                normalized_impl_candidates[..end].join(""),
-                if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
-            ));
-        }
-        true
+        report(normalized_impl_candidates, err)
     }
 
     /// Gets the parent trait chain start
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index b369c733871..16ecca254c7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -557,8 +557,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
                 } else if real_trait_pred != trait_pred {
                     // This branch addresses #87437.
-                    let obligation =
-                        self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, base_ty);
+                    let obligation = self.mk_trait_obligation_with_new_self_ty(
+                        param_env,
+                        real_trait_pred,
+                        base_ty,
+                    );
                     if self.predicate_may_hold(&obligation) {
                         err.span_suggestion_verbose(
                             span.shrink_to_lo(),