1
1
use super :: FnCtxt ;
2
2
3
3
use crate :: errors:: { AddReturnTypeSuggestion , ExpectedReturnTypeLabel } ;
4
+ use crate :: method:: probe:: { IsSuggestion , Mode , ProbeScope } ;
4
5
use rustc_ast:: util:: parser:: { ExprPrecedence , PREC_POSTFIX } ;
5
6
use rustc_errors:: { Applicability , Diagnostic , MultiSpan } ;
6
7
use rustc_hir as hir;
@@ -15,10 +16,11 @@ use rustc_infer::traits::{self, StatementAsExpression};
15
16
use rustc_middle:: lint:: in_external_macro;
16
17
use rustc_middle:: ty:: {
17
18
self , suggest_constraining_type_params, Binder , DefIdTree , IsSuggestable , ToPredicate , Ty ,
19
+ TypeVisitable ,
18
20
} ;
19
21
use 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 } ;
22
24
use rustc_trait_selection:: infer:: InferCtxtExt ;
23
25
use rustc_trait_selection:: traits:: error_reporting:: DefIdOrName ;
24
26
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
@@ -1236,6 +1238,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1236
1238
}
1237
1239
}
1238
1240
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
+
1239
1319
fn is_loop ( & self , id : hir:: HirId ) -> bool {
1240
1320
let node = self . tcx . hir ( ) . get ( id) ;
1241
1321
matches ! ( node, Node :: Expr ( Expr { kind: ExprKind :: Loop ( ..) , .. } ) )
0 commit comments