@@ -14,6 +14,7 @@ use crate::infer::{self, InferCtxt, TyCtxtInferExt};
1414use rustc_data_structures:: fx:: FxHashMap ;
1515use rustc_errors:: {
1616 pluralize, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
17+ Style ,
1718} ;
1819use rustc_hir as hir;
1920use rustc_hir:: def_id:: DefId ;
@@ -354,7 +355,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
354355 let have_alt_message = message. is_some ( ) || label. is_some ( ) ;
355356 let is_try_conversion = self . is_try_conversion ( span, trait_ref. def_id ( ) ) ;
356357 let is_unsize =
357- { Some ( trait_ref. def_id ( ) ) == self . tcx . lang_items ( ) . unsize_trait ( ) } ;
358+ Some ( trait_ref. def_id ( ) ) == self . tcx . lang_items ( ) . unsize_trait ( ) ;
358359 let ( message, note, append_const_msg) = if is_try_conversion {
359360 (
360361 Some ( format ! (
@@ -363,7 +364,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
363364 ) ) ,
364365 Some (
365366 "the question mark operation (`?`) implicitly performs a \
366- conversion on the error value using the `From` trait"
367+ conversion on the error value using the `From` trait"
367368 . to_owned ( ) ,
368369 ) ,
369370 Some ( None ) ,
@@ -519,10 +520,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
519520 }
520521
521522 self . suggest_floating_point_literal ( & obligation, & mut err, & trait_ref) ;
522- self . suggest_dereferences ( & obligation, & mut err, trait_predicate) ;
523- self . suggest_fn_call ( & obligation, & mut err, trait_predicate) ;
524- self . suggest_remove_reference ( & obligation, & mut err, trait_predicate) ;
525- self . suggest_semicolon_removal (
523+ let mut suggested =
524+ self . suggest_dereferences ( & obligation, & mut err, trait_predicate) ;
525+ suggested |= self . suggest_fn_call ( & obligation, & mut err, trait_predicate) ;
526+ suggested |=
527+ self . suggest_remove_reference ( & obligation, & mut err, trait_predicate) ;
528+ suggested |= self . suggest_semicolon_removal (
526529 & obligation,
527530 & mut err,
528531 span,
@@ -648,10 +651,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
648651 trait_predicate,
649652 obligation. cause . body_id ,
650653 ) ;
651- } else if !have_alt_message {
654+ } else if !suggested {
652655 // Can't show anything else useful, try to find similar impls.
653656 let impl_candidates = self . find_similar_impl_candidates ( trait_ref) ;
654- self . report_similar_impl_candidates ( impl_candidates, & mut err) ;
657+ self . report_similar_impl_candidates (
658+ impl_candidates,
659+ trait_ref,
660+ & mut err,
661+ ) ;
655662 }
656663
657664 // Changing mutability doesn't make a difference to whether we have
@@ -676,7 +683,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
676683 } ) ;
677684 let unit_obligation = obligation. with ( predicate. to_predicate ( tcx) ) ;
678685 if self . predicate_may_hold ( & unit_obligation) {
679- err. note ( "this trait is implemented for `()`" ) ;
680686 err. note (
681687 "this error might have been caused by changes to \
682688 Rust's type-inference algorithm (see issue #48950 \
@@ -1301,8 +1307,9 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
13011307 fn report_similar_impl_candidates (
13021308 & self ,
13031309 impl_candidates : Vec < ImplCandidate < ' tcx > > ,
1310+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
13041311 err : & mut Diagnostic ,
1305- ) ;
1312+ ) -> bool ;
13061313
13071314 /// Gets the parent trait chain start
13081315 fn get_parent_trait_ref (
@@ -1313,7 +1320,11 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
13131320 /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
13141321 /// with the same path as `trait_ref`, a help message about
13151322 /// a probable version mismatch is added to `err`
1316- fn note_version_mismatch ( & self , err : & mut Diagnostic , trait_ref : & ty:: PolyTraitRef < ' tcx > ) ;
1323+ fn note_version_mismatch (
1324+ & self ,
1325+ err : & mut Diagnostic ,
1326+ trait_ref : & ty:: PolyTraitRef < ' tcx > ,
1327+ ) -> bool ;
13171328
13181329 /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
13191330 /// `trait_ref`.
@@ -1675,10 +1686,63 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
16751686 fn report_similar_impl_candidates (
16761687 & self ,
16771688 impl_candidates : Vec < ImplCandidate < ' tcx > > ,
1689+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
16781690 err : & mut Diagnostic ,
1679- ) {
1691+ ) -> bool {
1692+ let def_id = trait_ref. def_id ( ) ;
16801693 if impl_candidates. is_empty ( ) {
1681- return ;
1694+ if self . tcx . trait_is_auto ( def_id)
1695+ || self . tcx . lang_items ( ) . items ( ) . contains ( & Some ( def_id) )
1696+ || self . tcx . get_diagnostic_name ( def_id) . is_some ( )
1697+ {
1698+ // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
1699+ return false ;
1700+ }
1701+ let mut normalized_impl_candidates: Vec < _ > = self
1702+ . tcx
1703+ . all_impls ( def_id)
1704+ // Ignore automatically derived impls and `!Trait` impls.
1705+ . filter ( |& def_id| {
1706+ self . tcx . impl_polarity ( def_id) != ty:: ImplPolarity :: Negative
1707+ || self . tcx . is_builtin_derive ( def_id)
1708+ } )
1709+ . filter_map ( |def_id| self . tcx . impl_trait_ref ( def_id) )
1710+ // Avoid mentioning type parameters.
1711+ . filter ( |trait_ref| !matches ! ( trait_ref. self_ty( ) . kind( ) , ty:: Param ( _) ) )
1712+ . map ( |trait_ref| format ! ( "\n {}" , trait_ref. self_ty( ) ) )
1713+ . collect ( ) ;
1714+ normalized_impl_candidates. sort ( ) ;
1715+ normalized_impl_candidates. dedup ( ) ;
1716+ let len = normalized_impl_candidates. len ( ) ;
1717+ if len == 0 {
1718+ return false ;
1719+ }
1720+ if len == 1 {
1721+ err. highlighted_help ( vec ! [
1722+ (
1723+ format!(
1724+ "the trait `{}` is implemented for `" ,
1725+ trait_ref. print_only_trait_path( )
1726+ ) ,
1727+ Style :: NoStyle ,
1728+ ) ,
1729+ ( normalized_impl_candidates[ 0 ] . trim( ) . to_string( ) , Style :: Highlight ) ,
1730+ ( "`" . to_string( ) , Style :: NoStyle ) ,
1731+ ] ) ;
1732+ return true ;
1733+ }
1734+ let end = if normalized_impl_candidates. len ( ) <= 9 {
1735+ normalized_impl_candidates. len ( )
1736+ } else {
1737+ 8
1738+ } ;
1739+ err. help ( & format ! (
1740+ "the following other types implement trait `{}`:{}{}" ,
1741+ trait_ref. print_only_trait_path( ) ,
1742+ normalized_impl_candidates[ ..end] . join( "" ) ,
1743+ if len > 9 { format!( "\n and {} others" , len - 8 ) } else { String :: new( ) }
1744+ ) ) ;
1745+ return true ;
16821746 }
16831747
16841748 let len = impl_candidates. len ( ) ;
@@ -1703,6 +1767,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17031767 //
17041768 // Prefer more similar candidates first, then sort lexicographically
17051769 // by their normalized string representation.
1770+ let first_candidate = impl_candidates. get ( 0 ) . map ( |candidate| candidate. trait_ref ) ;
17061771 let mut normalized_impl_candidates_and_similarities = impl_candidates
17071772 . into_iter ( )
17081773 . map ( |ImplCandidate { trait_ref, similarity } | {
@@ -1711,17 +1776,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17111776 } )
17121777 . collect :: < Vec < _ > > ( ) ;
17131778 normalized_impl_candidates_and_similarities. sort ( ) ;
1779+ normalized_impl_candidates_and_similarities. dedup ( ) ;
17141780
17151781 let normalized_impl_candidates = normalized_impl_candidates_and_similarities
17161782 . into_iter ( )
17171783 . map ( |( _, normalized) | normalized)
17181784 . collect :: < Vec < _ > > ( ) ;
17191785
1720- err. help ( & format ! (
1721- "the following implementations were found:{}{}" ,
1722- normalized_impl_candidates[ ..end] . join( "" ) ,
1723- if len > 5 { format!( "\n and {} others" , len - 4 ) } else { String :: new( ) }
1724- ) ) ;
1786+ if normalized_impl_candidates. len ( ) == 1 {
1787+ err. highlighted_help ( vec ! [
1788+ (
1789+ format!(
1790+ "the trait `{}` is implemented for `" ,
1791+ first_candidate. unwrap( ) . print_only_trait_path( )
1792+ ) ,
1793+ Style :: NoStyle ,
1794+ ) ,
1795+ ( first_candidate. unwrap( ) . self_ty( ) . to_string( ) , Style :: Highlight ) ,
1796+ ( "`" . to_string( ) , Style :: NoStyle ) ,
1797+ ] ) ;
1798+ } else {
1799+ err. help ( & format ! (
1800+ "the following implementations were found:{}{}" ,
1801+ normalized_impl_candidates[ ..end] . join( "" ) ,
1802+ if len > 9 { format!( "\n and {} others" , len - 8 ) } else { String :: new( ) }
1803+ ) ) ;
1804+ }
1805+ true
17251806 }
17261807
17271808 /// Gets the parent trait chain start
@@ -1752,7 +1833,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17521833 /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
17531834 /// with the same path as `trait_ref`, a help message about
17541835 /// a probable version mismatch is added to `err`
1755- fn note_version_mismatch ( & self , err : & mut Diagnostic , trait_ref : & ty:: PolyTraitRef < ' tcx > ) {
1836+ fn note_version_mismatch (
1837+ & self ,
1838+ err : & mut Diagnostic ,
1839+ trait_ref : & ty:: PolyTraitRef < ' tcx > ,
1840+ ) -> bool {
17561841 let get_trait_impl = |trait_def_id| {
17571842 self . tcx . find_map_relevant_impl ( trait_def_id, trait_ref. skip_binder ( ) . self_ty ( ) , Some )
17581843 } ;
@@ -1763,6 +1848,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17631848 . filter ( |trait_def_id| * trait_def_id != trait_ref. def_id ( ) )
17641849 . filter ( |trait_def_id| self . tcx . def_path_str ( * trait_def_id) == required_trait_path)
17651850 . collect ( ) ;
1851+ let mut suggested = false ;
17661852 for trait_with_same_path in traits_with_same_path {
17671853 if let Some ( impl_def_id) = get_trait_impl ( trait_with_same_path) {
17681854 let impl_span = self . tcx . def_span ( impl_def_id) ;
@@ -1773,8 +1859,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
17731859 trait_crate
17741860 ) ;
17751861 err. note ( & crate_msg) ;
1862+ suggested = true ;
17761863 }
17771864 }
1865+ suggested
17781866 }
17791867
17801868 fn mk_trait_obligation_with_new_self_ty (
0 commit comments