@@ -14,6 +14,7 @@ use crate::infer::{self, InferCtxt, TyCtxtInferExt};
14
14
use rustc_data_structures:: fx:: FxHashMap ;
15
15
use rustc_errors:: {
16
16
pluralize, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
17
+ Style ,
17
18
} ;
18
19
use rustc_hir as hir;
19
20
use rustc_hir:: def_id:: DefId ;
@@ -354,7 +355,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
354
355
let have_alt_message = message. is_some ( ) || label. is_some ( ) ;
355
356
let is_try_conversion = self . is_try_conversion ( span, trait_ref. def_id ( ) ) ;
356
357
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 ( ) ;
358
359
let ( message, note, append_const_msg) = if is_try_conversion {
359
360
(
360
361
Some ( format ! (
@@ -363,7 +364,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
363
364
) ) ,
364
365
Some (
365
366
"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"
367
368
. to_owned ( ) ,
368
369
) ,
369
370
Some ( None ) ,
@@ -519,10 +520,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
519
520
}
520
521
521
522
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 (
526
529
& obligation,
527
530
& mut err,
528
531
span,
@@ -648,10 +651,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
648
651
trait_predicate,
649
652
obligation. cause . body_id ,
650
653
) ;
651
- } else if !have_alt_message {
654
+ } else if !suggested {
652
655
// Can't show anything else useful, try to find similar impls.
653
656
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
+ ) ;
655
662
}
656
663
657
664
// Changing mutability doesn't make a difference to whether we have
@@ -676,7 +683,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
676
683
} ) ;
677
684
let unit_obligation = obligation. with ( predicate. to_predicate ( tcx) ) ;
678
685
if self . predicate_may_hold ( & unit_obligation) {
679
- err. note ( "this trait is implemented for `()`" ) ;
680
686
err. note (
681
687
"this error might have been caused by changes to \
682
688
Rust's type-inference algorithm (see issue #48950 \
@@ -1301,8 +1307,9 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
1301
1307
fn report_similar_impl_candidates (
1302
1308
& self ,
1303
1309
impl_candidates : Vec < ImplCandidate < ' tcx > > ,
1310
+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
1304
1311
err : & mut Diagnostic ,
1305
- ) ;
1312
+ ) -> bool ;
1306
1313
1307
1314
/// Gets the parent trait chain start
1308
1315
fn get_parent_trait_ref (
@@ -1313,7 +1320,11 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
1313
1320
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
1314
1321
/// with the same path as `trait_ref`, a help message about
1315
1322
/// 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 ;
1317
1328
1318
1329
/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
1319
1330
/// `trait_ref`.
@@ -1675,10 +1686,63 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1675
1686
fn report_similar_impl_candidates (
1676
1687
& self ,
1677
1688
impl_candidates : Vec < ImplCandidate < ' tcx > > ,
1689
+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
1678
1690
err : & mut Diagnostic ,
1679
- ) {
1691
+ ) -> bool {
1692
+ let def_id = trait_ref. def_id ( ) ;
1680
1693
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 ;
1682
1746
}
1683
1747
1684
1748
let len = impl_candidates. len ( ) ;
@@ -1703,6 +1767,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1703
1767
//
1704
1768
// Prefer more similar candidates first, then sort lexicographically
1705
1769
// by their normalized string representation.
1770
+ let first_candidate = impl_candidates. get ( 0 ) . map ( |candidate| candidate. trait_ref ) ;
1706
1771
let mut normalized_impl_candidates_and_similarities = impl_candidates
1707
1772
. into_iter ( )
1708
1773
. map ( |ImplCandidate { trait_ref, similarity } | {
@@ -1711,17 +1776,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1711
1776
} )
1712
1777
. collect :: < Vec < _ > > ( ) ;
1713
1778
normalized_impl_candidates_and_similarities. sort ( ) ;
1779
+ normalized_impl_candidates_and_similarities. dedup ( ) ;
1714
1780
1715
1781
let normalized_impl_candidates = normalized_impl_candidates_and_similarities
1716
1782
. into_iter ( )
1717
1783
. map ( |( _, normalized) | normalized)
1718
1784
. collect :: < Vec < _ > > ( ) ;
1719
1785
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
1725
1806
}
1726
1807
1727
1808
/// Gets the parent trait chain start
@@ -1752,7 +1833,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1752
1833
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
1753
1834
/// with the same path as `trait_ref`, a help message about
1754
1835
/// 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 {
1756
1841
let get_trait_impl = |trait_def_id| {
1757
1842
self . tcx . find_map_relevant_impl ( trait_def_id, trait_ref. skip_binder ( ) . self_ty ( ) , Some )
1758
1843
} ;
@@ -1763,6 +1848,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1763
1848
. filter ( |trait_def_id| * trait_def_id != trait_ref. def_id ( ) )
1764
1849
. filter ( |trait_def_id| self . tcx . def_path_str ( * trait_def_id) == required_trait_path)
1765
1850
. collect ( ) ;
1851
+ let mut suggested = false ;
1766
1852
for trait_with_same_path in traits_with_same_path {
1767
1853
if let Some ( impl_def_id) = get_trait_impl ( trait_with_same_path) {
1768
1854
let impl_span = self . tcx . def_span ( impl_def_id) ;
@@ -1773,8 +1859,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1773
1859
trait_crate
1774
1860
) ;
1775
1861
err. note ( & crate_msg) ;
1862
+ suggested = true ;
1776
1863
}
1777
1864
}
1865
+ suggested
1778
1866
}
1779
1867
1780
1868
fn mk_trait_obligation_with_new_self_ty (
0 commit comments