@@ -16,8 +16,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
1616use rustc_middle:: traits:: util:: supertraits;
1717use rustc_middle:: ty:: fast_reject:: { simplify_type, TreatParams } ;
1818use rustc_middle:: ty:: print:: with_crate_prefix;
19- use rustc_middle:: ty:: ToPolyTraitRef ;
2019use rustc_middle:: ty:: { self , DefIdTree , ToPredicate , Ty , TyCtxt , TypeVisitable } ;
20+ use rustc_middle:: ty:: { IsSuggestable , ToPolyTraitRef } ;
2121use rustc_span:: symbol:: { kw, sym, Ident } ;
2222use rustc_span:: Symbol ;
2323use rustc_span:: { lev_distance, source_map, ExpnKind , FileName , MacroKind , Span } ;
@@ -30,7 +30,7 @@ use rustc_trait_selection::traits::{
3030use std:: cmp:: Ordering ;
3131use std:: iter;
3232
33- use super :: probe:: { Mode , ProbeScope } ;
33+ use super :: probe:: { IsSuggestion , Mode , ProbeScope } ;
3434use super :: { CandidateSource , MethodError , NoMatchData } ;
3535
3636impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -1069,6 +1069,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10691069 }
10701070 }
10711071
1072+ self . check_for_deref_method ( & mut err, source, rcvr_ty, item_name) ;
1073+
10721074 return Some ( err) ;
10731075 }
10741076
@@ -1651,6 +1653,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16511653 }
16521654 }
16531655
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+
16541712 /// Print out the type for use in value namespace.
16551713 fn ty_to_value_string ( & self , ty : Ty < ' tcx > ) -> String {
16561714 match ty. kind ( ) {
0 commit comments