1
+ // ignore-tidy-filelength :(
2
+
1
3
mod ambiguity;
2
4
pub mod on_unimplemented;
3
5
pub mod suggestions;
@@ -67,6 +69,7 @@ pub enum CandidateSimilarity {
67
69
pub struct ImplCandidate < ' tcx > {
68
70
pub trait_ref : ty:: TraitRef < ' tcx > ,
69
71
pub similarity : CandidateSimilarity ,
72
+ impl_def_id : DefId ,
70
73
}
71
74
72
75
enum GetSafeTransmuteErrorAndReason {
@@ -1331,6 +1334,7 @@ trait InferCtxtPrivExt<'tcx> {
1331
1334
body_def_id : LocalDefId ,
1332
1335
err : & mut Diagnostic ,
1333
1336
other : bool ,
1337
+ param_env : ty:: ParamEnv < ' tcx > ,
1334
1338
) -> bool ;
1335
1339
1336
1340
fn report_similar_impl_candidates_for_root_obligation (
@@ -1918,8 +1922,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1918
1922
1919
1923
let imp = self . tcx . impl_trait_ref ( def_id) . unwrap ( ) . skip_binder ( ) ;
1920
1924
1921
- self . fuzzy_match_tys ( trait_pred. skip_binder ( ) . self_ty ( ) , imp. self_ty ( ) , false )
1922
- . map ( |similarity| ImplCandidate { trait_ref : imp, similarity } )
1925
+ self . fuzzy_match_tys ( trait_pred. skip_binder ( ) . self_ty ( ) , imp. self_ty ( ) , false ) . map (
1926
+ |similarity| ImplCandidate { trait_ref : imp, similarity, impl_def_id : def_id } ,
1927
+ )
1923
1928
} )
1924
1929
. collect ( ) ;
1925
1930
if candidates. iter ( ) . any ( |c| matches ! ( c. similarity, CandidateSimilarity :: Exact { .. } ) ) {
@@ -1938,7 +1943,82 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1938
1943
body_def_id : LocalDefId ,
1939
1944
err : & mut Diagnostic ,
1940
1945
other : bool ,
1946
+ param_env : ty:: ParamEnv < ' tcx > ,
1941
1947
) -> bool {
1948
+ // If we have a single implementation, try to unify it with the trait ref
1949
+ // that failed. This should uncover a better hint for what *is* implemented.
1950
+ if let [ single] = & impl_candidates {
1951
+ if self . probe ( |_| {
1952
+ let ocx = ObligationCtxt :: new ( self ) ;
1953
+ let obligation_trait_ref = self . instantiate_binder_with_placeholders ( trait_ref) ;
1954
+ let impl_args = self . fresh_args_for_item ( DUMMY_SP , single. impl_def_id ) ;
1955
+ let impl_trait_ref = ocx. normalize (
1956
+ & ObligationCause :: dummy ( ) ,
1957
+ param_env,
1958
+ ty:: EarlyBinder :: bind ( single. trait_ref ) . instantiate ( self . tcx , impl_args) ,
1959
+ ) ;
1960
+
1961
+ ocx. register_obligations (
1962
+ self . tcx
1963
+ . predicates_of ( single. impl_def_id )
1964
+ . instantiate ( self . tcx , impl_args)
1965
+ . into_iter ( )
1966
+ . map ( |( clause, _) | {
1967
+ Obligation :: new ( self . tcx , ObligationCause :: dummy ( ) , param_env, clause)
1968
+ } ) ,
1969
+ ) ;
1970
+ if !ocx. select_where_possible ( ) . is_empty ( ) {
1971
+ return false ;
1972
+ }
1973
+
1974
+ let mut terrs = vec ! [ ] ;
1975
+ for ( obligation_arg, impl_arg) in
1976
+ std:: iter:: zip ( obligation_trait_ref. args , impl_trait_ref. args )
1977
+ {
1978
+ if let Err ( terr) =
1979
+ ocx. eq ( & ObligationCause :: dummy ( ) , param_env, impl_arg, obligation_arg)
1980
+ {
1981
+ terrs. push ( terr) ;
1982
+ }
1983
+ if !ocx. select_where_possible ( ) . is_empty ( ) {
1984
+ return false ;
1985
+ }
1986
+ }
1987
+
1988
+ // Literally nothing unified, just give up.
1989
+ if terrs. len ( ) == impl_trait_ref. args . len ( ) {
1990
+ return false ;
1991
+ }
1992
+
1993
+ let cand =
1994
+ self . resolve_vars_if_possible ( impl_trait_ref) . fold_with ( & mut BottomUpFolder {
1995
+ tcx : self . tcx ,
1996
+ ty_op : |ty| ty,
1997
+ lt_op : |lt| lt,
1998
+ ct_op : |ct| ct. normalize ( self . tcx , ty:: ParamEnv :: empty ( ) ) ,
1999
+ } ) ;
2000
+ err. highlighted_help ( vec ! [
2001
+ ( format!( "the trait `{}` " , cand. print_only_trait_path( ) ) , Style :: NoStyle ) ,
2002
+ ( "is" . to_string( ) , Style :: Highlight ) ,
2003
+ ( " implemented for `" . to_string( ) , Style :: NoStyle ) ,
2004
+ ( cand. self_ty( ) . to_string( ) , Style :: Highlight ) ,
2005
+ ( "`" . to_string( ) , Style :: NoStyle ) ,
2006
+ ] ) ;
2007
+
2008
+ if let [ TypeError :: Sorts ( exp_found) ] = & terrs[ ..] {
2009
+ let exp_found = self . resolve_vars_if_possible ( * exp_found) ;
2010
+ err. help ( format ! (
2011
+ "for that trait implementation, expected `{}`, found `{}`" ,
2012
+ exp_found. expected, exp_found. found
2013
+ ) ) ;
2014
+ }
2015
+
2016
+ true
2017
+ } ) {
2018
+ return true ;
2019
+ }
2020
+ }
2021
+
1942
2022
let other = if other { "other " } else { "" } ;
1943
2023
let report = |candidates : Vec < TraitRef < ' tcx > > , err : & mut Diagnostic | {
1944
2024
if candidates. is_empty ( ) {
@@ -2062,9 +2142,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
2062
2142
} )
2063
2143
. collect ( ) ;
2064
2144
impl_candidates. sort_by_key ( |cand| ( cand. similarity , cand. trait_ref ) ) ;
2145
+ let mut impl_candidates: Vec < _ > =
2146
+ impl_candidates. into_iter ( ) . map ( |cand| cand. trait_ref ) . collect ( ) ;
2065
2147
impl_candidates. dedup ( ) ;
2066
2148
2067
- report ( impl_candidates. into_iter ( ) . map ( |cand| cand . trait_ref ) . collect ( ) , err)
2149
+ report ( impl_candidates, err)
2068
2150
}
2069
2151
2070
2152
fn report_similar_impl_candidates_for_root_obligation (
@@ -2108,6 +2190,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
2108
2190
body_def_id,
2109
2191
err,
2110
2192
true ,
2193
+ obligation. param_env ,
2111
2194
) ;
2112
2195
}
2113
2196
}
@@ -2316,6 +2399,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
2316
2399
obligation. cause . body_id ,
2317
2400
& mut err,
2318
2401
false ,
2402
+ obligation. param_env ,
2319
2403
) ;
2320
2404
}
2321
2405
}
@@ -3051,6 +3135,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3051
3135
body_def_id,
3052
3136
err,
3053
3137
true ,
3138
+ obligation. param_env ,
3054
3139
) {
3055
3140
self . report_similar_impl_candidates_for_root_obligation (
3056
3141
& obligation,
0 commit comments