@@ -7,6 +7,9 @@ use crate::errors::NoAssociatedItem;
77use crate :: Expectation ;
88use crate :: FnCtxt ;
99use rustc_ast:: ast:: Mutability ;
10+ use rustc_ast:: token;
11+ use rustc_ast:: tokenstream:: TokenTree ;
12+ use rustc_ast:: { AttrArgs , AttrKind , Attribute , DelimArgs , NormalAttr } ;
1013use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
1114use rustc_errors:: StashKey ;
1215use rustc_errors:: {
@@ -24,6 +27,7 @@ use rustc_infer::infer::{
2427 type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ,
2528 RegionVariableOrigin ,
2629} ;
30+ use rustc_macros:: Diagnostic ;
2731use rustc_middle:: infer:: unify_key:: { ConstVariableOrigin , ConstVariableOriginKind } ;
2832use rustc_middle:: traits:: util:: supertraits;
2933use rustc_middle:: ty:: fast_reject:: DeepRejectCtxt ;
@@ -48,6 +52,42 @@ use rustc_hir::intravisit::Visitor;
4852use std:: cmp:: { self , Ordering } ;
4953use std:: iter;
5054
55+ #[ derive( Debug ) ]
56+ struct ConfusablesDirective {
57+ names : Vec < String > ,
58+ }
59+
60+ #[ derive( Diagnostic ) ]
61+ #[ diag( hir_typeck_invalid_rustc_confusable_attr) ]
62+ struct ConfusablesDirectiveParseErr {
63+ #[ primary_span]
64+ #[ label]
65+ span : Span ,
66+ }
67+
68+ impl ConfusablesDirective {
69+ fn try_parse ( attr : & NormalAttr ) -> Result < Self , ConfusablesDirectiveParseErr > {
70+ let AttrArgs :: Delimited ( DelimArgs { tokens, .. } ) = & attr. item . args else {
71+ return Err ( ConfusablesDirectiveParseErr {
72+ span : attr. item . span ( ) ,
73+ } ) ;
74+ } ;
75+
76+ let mut names = Vec :: new ( ) ;
77+ for tok in tokens. trees ( ) {
78+ if let TokenTree :: Token ( tok, _) = tok
79+ && let token:: Token { kind, .. } = tok
80+ && let token:: TokenKind :: Literal ( lit) = kind
81+ && let token:: Lit { kind : token:: LitKind :: Str , symbol, .. } = lit
82+ {
83+ names. push ( symbol. to_string ( ) ) ;
84+ }
85+ }
86+
87+ Ok ( ConfusablesDirective { names } )
88+ }
89+ }
90+
5191impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
5292 fn is_fn_ty ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
5393 let tcx = self . tcx ;
@@ -1026,6 +1066,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10261066 "the {item_kind} was found for\n {}{}" ,
10271067 type_candidates, additional_types
10281068 ) ) ;
1069+ } else {
1070+ let mut candidate_confusable = None ;
1071+
1072+ for inherent_impl_did in self . tcx . inherent_impls ( adt. did ( ) ) {
1073+ for inherent_method in
1074+ self . tcx . associated_items ( inherent_impl_did) . in_definition_order ( )
1075+ {
1076+ if let Some ( Attribute { kind : AttrKind :: Normal ( attr) , .. } ) = self
1077+ . tcx
1078+ . get_attr ( inherent_method. def_id , sym:: rustc_confusables)
1079+ {
1080+ match ConfusablesDirective :: try_parse ( attr) {
1081+ Ok ( c) => {
1082+ if c. names . contains ( & item_name. to_string ( ) ) {
1083+ candidate_confusable = Some ( inherent_method) ;
1084+ break ;
1085+ }
1086+ }
1087+ Err ( e) => {
1088+ self . sess ( ) . emit_err ( e) ;
1089+ break ;
1090+ }
1091+ }
1092+ }
1093+ }
1094+ }
1095+
1096+ if let Some ( candidate_confusable) = candidate_confusable {
1097+ err. span_suggestion_verbose (
1098+ item_name. span ,
1099+ format ! (
1100+ "you might have meant to use `{}`" ,
1101+ candidate_confusable. name. as_str( )
1102+ ) ,
1103+ candidate_confusable. name . as_str ( ) ,
1104+ Applicability :: MaybeIncorrect ,
1105+ ) ;
1106+ }
10291107 }
10301108 }
10311109 } else {
0 commit comments