@@ -16,8 +16,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
16
16
use rustc_middle:: traits:: util:: supertraits;
17
17
use rustc_middle:: ty:: fast_reject:: { simplify_type, TreatParams } ;
18
18
use rustc_middle:: ty:: print:: with_crate_prefix;
19
- use rustc_middle:: ty:: ToPolyTraitRef ;
20
19
use rustc_middle:: ty:: { self , DefIdTree , ToPredicate , Ty , TyCtxt , TypeVisitable } ;
20
+ use rustc_middle:: ty:: { IsSuggestable , ToPolyTraitRef } ;
21
21
use rustc_span:: symbol:: { kw, sym, Ident } ;
22
22
use rustc_span:: Symbol ;
23
23
use rustc_span:: { lev_distance, source_map, ExpnKind , FileName , MacroKind , Span } ;
@@ -30,7 +30,7 @@ use rustc_trait_selection::traits::{
30
30
use std:: cmp:: Ordering ;
31
31
use std:: iter;
32
32
33
- use super :: probe:: { Mode , ProbeScope } ;
33
+ use super :: probe:: { IsSuggestion , Mode , ProbeScope } ;
34
34
use super :: { CandidateSource , MethodError , NoMatchData } ;
35
35
36
36
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -1069,6 +1069,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1069
1069
}
1070
1070
}
1071
1071
1072
+ self . check_for_deref_method ( & mut err, source, rcvr_ty, item_name) ;
1073
+
1072
1074
return Some ( err) ;
1073
1075
}
1074
1076
@@ -1651,6 +1653,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1651
1653
}
1652
1654
}
1653
1655
1656
+ fn check_for_deref_method (
1657
+ & self ,
1658
+ err : & mut Diagnostic ,
1659
+ self_source : SelfSource < ' tcx > ,
1660
+ rcvr_ty : Ty < ' tcx > ,
1661
+ item_name : Ident ,
1662
+ ) {
1663
+ let SelfSource :: QPath ( ty) = self_source else { return ; } ;
1664
+ for ( deref_ty, _) in self . autoderef ( rustc_span:: DUMMY_SP , rcvr_ty) . skip ( 1 ) {
1665
+ if let Ok ( pick) = self . probe_for_name (
1666
+ ty. span ,
1667
+ Mode :: Path ,
1668
+ item_name,
1669
+ IsSuggestion ( true ) ,
1670
+ deref_ty,
1671
+ ty. hir_id ,
1672
+ ProbeScope :: TraitsInScope ,
1673
+ ) {
1674
+ if deref_ty. is_suggestable ( self . tcx , true )
1675
+ // If this method receives `&self`, then the provided
1676
+ // argument _should_ coerce, so it's valid to suggest
1677
+ // just changing the path.
1678
+ && pick. item . fn_has_self_parameter
1679
+ && let Some ( self_ty) =
1680
+ self . tcx . fn_sig ( pick. item . def_id ) . inputs ( ) . skip_binder ( ) . get ( 0 )
1681
+ && self_ty. is_ref ( )
1682
+ {
1683
+ let suggested_path = match deref_ty. kind ( ) {
1684
+ ty:: Bool
1685
+ | ty:: Char
1686
+ | ty:: Int ( _)
1687
+ | ty:: Uint ( _)
1688
+ | ty:: Float ( _)
1689
+ | ty:: Adt ( _, _)
1690
+ | ty:: Str
1691
+ | ty:: Projection ( _)
1692
+ | ty:: Param ( _) => format ! ( "{deref_ty}" ) ,
1693
+ _ => format ! ( "<{deref_ty}>" ) ,
1694
+ } ;
1695
+ err. span_suggestion_verbose (
1696
+ ty. span ,
1697
+ format ! ( "the function `{item_name}` is implemented on `{deref_ty}`" ) ,
1698
+ suggested_path,
1699
+ Applicability :: MaybeIncorrect ,
1700
+ ) ;
1701
+ } else {
1702
+ err. span_note (
1703
+ ty. span ,
1704
+ format ! ( "the function `{item_name}` is implemented on `{deref_ty}`" ) ,
1705
+ ) ;
1706
+ }
1707
+ return ;
1708
+ }
1709
+ }
1710
+ }
1711
+
1654
1712
/// Print out the type for use in value namespace.
1655
1713
fn ty_to_value_string ( & self , ty : Ty < ' tcx > ) -> String {
1656
1714
match ty. kind ( ) {
0 commit comments