11use super :: FnCtxt ;
22
33use crate :: errors:: { AddReturnTypeSuggestion , ExpectedReturnTypeLabel } ;
4+ use crate :: method:: probe:: { IsSuggestion , Mode , ProbeScope } ;
45use rustc_ast:: util:: parser:: { ExprPrecedence , PREC_POSTFIX } ;
56use rustc_errors:: { Applicability , Diagnostic , MultiSpan } ;
67use rustc_hir as hir;
@@ -15,10 +16,11 @@ use rustc_infer::traits::{self, StatementAsExpression};
1516use rustc_middle:: lint:: in_external_macro;
1617use rustc_middle:: ty:: {
1718 self , suggest_constraining_type_params, Binder , DefIdTree , IsSuggestable , ToPredicate , Ty ,
19+ TypeVisitable ,
1820} ;
1921use rustc_session:: errors:: ExprParenthesesNeeded ;
20- use rustc_span:: symbol:: sym;
21- use rustc_span:: Span ;
22+ use rustc_span:: symbol:: { sym, Ident } ;
23+ use rustc_span:: { Span , Symbol } ;
2224use rustc_trait_selection:: infer:: InferCtxtExt ;
2325use rustc_trait_selection:: traits:: error_reporting:: DefIdOrName ;
2426use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
@@ -1236,6 +1238,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12361238 }
12371239 }
12381240
1241+ pub ( crate ) fn suggest_associated_const (
1242+ & self ,
1243+ err : & mut Diagnostic ,
1244+ expr : & hir:: Expr < ' _ > ,
1245+ expected_ty : Ty < ' tcx > ,
1246+ ) -> bool {
1247+ let Some ( ( DefKind :: AssocFn , old_def_id) ) = self . typeck_results . borrow ( ) . type_dependent_def ( expr. hir_id ) else {
1248+ return false ;
1249+ } ;
1250+ let old_item_name = self . tcx . item_name ( old_def_id) ;
1251+ let capitalized_name = Symbol :: intern ( & old_item_name. as_str ( ) . to_uppercase ( ) ) ;
1252+ if old_item_name == capitalized_name {
1253+ return false ;
1254+ }
1255+ let ( item, segment) = match expr. kind {
1256+ hir:: ExprKind :: Path ( QPath :: Resolved (
1257+ Some ( ty) ,
1258+ hir:: Path { segments : [ segment] , .. } ,
1259+ ) )
1260+ | hir:: ExprKind :: Path ( QPath :: TypeRelative ( ty, segment) ) => {
1261+ let self_ty = <dyn AstConv < ' _ > >:: ast_ty_to_ty ( self , ty) ;
1262+ if let Ok ( pick) = self . probe_for_name (
1263+ Mode :: Path ,
1264+ Ident :: new ( capitalized_name, segment. ident . span ) ,
1265+ IsSuggestion ( true ) ,
1266+ self_ty,
1267+ expr. hir_id ,
1268+ ProbeScope :: TraitsInScope ,
1269+ ) {
1270+ ( pick. item , segment)
1271+ } else {
1272+ return false ;
1273+ }
1274+ }
1275+ hir:: ExprKind :: Path ( QPath :: Resolved (
1276+ None ,
1277+ hir:: Path { segments : [ .., segment] , .. } ,
1278+ ) ) => {
1279+ // we resolved through some path that doesn't end in the item name,
1280+ // better not do a bad suggestion by accident.
1281+ if old_item_name != segment. ident . name {
1282+ return false ;
1283+ }
1284+ if let Some ( item) = self
1285+ . tcx
1286+ . associated_items ( self . tcx . parent ( old_def_id) )
1287+ . filter_by_name_unhygienic ( capitalized_name)
1288+ . next ( )
1289+ {
1290+ ( * item, segment)
1291+ } else {
1292+ return false ;
1293+ }
1294+ }
1295+ _ => return false ,
1296+ } ;
1297+ if item. def_id == old_def_id || self . tcx . def_kind ( item. def_id ) != DefKind :: AssocConst {
1298+ // Same item
1299+ return false ;
1300+ }
1301+ let item_ty = self . tcx . type_of ( item. def_id ) ;
1302+ // FIXME(compiler-errors): This check is *so* rudimentary
1303+ if item_ty. needs_subst ( ) {
1304+ return false ;
1305+ }
1306+ if self . can_coerce ( item_ty, expected_ty) {
1307+ err. span_suggestion_verbose (
1308+ segment. ident . span ,
1309+ format ! ( "try referring to the associated const `{capitalized_name}` instead" , ) ,
1310+ capitalized_name,
1311+ Applicability :: MachineApplicable ,
1312+ ) ;
1313+ true
1314+ } else {
1315+ false
1316+ }
1317+ }
1318+
12391319 fn is_loop ( & self , id : hir:: HirId ) -> bool {
12401320 let node = self . tcx . hir ( ) . get ( id) ;
12411321 matches ! ( node, Node :: Expr ( Expr { kind: ExprKind :: Loop ( ..) , .. } ) )
0 commit comments