@@ -7,6 +7,9 @@ use crate::errors::NoAssociatedItem;
7
7
use crate :: Expectation ;
8
8
use crate :: FnCtxt ;
9
9
use rustc_ast:: ast:: Mutability ;
10
+ use rustc_ast:: token;
11
+ use rustc_ast:: tokenstream:: TokenTree ;
12
+ use rustc_ast:: { AttrArgs , AttrKind , Attribute , DelimArgs , NormalAttr } ;
10
13
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
11
14
use rustc_errors:: StashKey ;
12
15
use rustc_errors:: {
@@ -24,6 +27,7 @@ use rustc_infer::infer::{
24
27
type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ,
25
28
RegionVariableOrigin ,
26
29
} ;
30
+ use rustc_macros:: Diagnostic ;
27
31
use rustc_middle:: infer:: unify_key:: { ConstVariableOrigin , ConstVariableOriginKind } ;
28
32
use rustc_middle:: traits:: util:: supertraits;
29
33
use rustc_middle:: ty:: fast_reject:: DeepRejectCtxt ;
@@ -48,6 +52,42 @@ use rustc_hir::intravisit::Visitor;
48
52
use std:: cmp:: { self , Ordering } ;
49
53
use std:: iter;
50
54
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
+
51
91
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
52
92
fn is_fn_ty ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
53
93
let tcx = self . tcx ;
@@ -1026,6 +1066,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1026
1066
"the {item_kind} was found for\n {}{}" ,
1027
1067
type_candidates, additional_types
1028
1068
) ) ;
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
+ }
1029
1107
}
1030
1108
}
1031
1109
} else {
0 commit comments