@@ -5,6 +5,7 @@ use crate::errors;
5
5
use crate :: FnCtxt ;
6
6
use rustc_ast:: ast:: Mutability ;
7
7
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
8
+ use rustc_errors:: StashKey ;
8
9
use rustc_errors:: {
9
10
pluralize, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
10
11
MultiSpan ,
@@ -13,6 +14,8 @@ use rustc_hir as hir;
13
14
use rustc_hir:: def:: DefKind ;
14
15
use rustc_hir:: def_id:: DefId ;
15
16
use rustc_hir:: lang_items:: LangItem ;
17
+ use rustc_hir:: PatKind :: Binding ;
18
+ use rustc_hir:: PathSegment ;
16
19
use rustc_hir:: { ExprKind , Node , QPath } ;
17
20
use rustc_infer:: infer:: {
18
21
type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ,
@@ -35,11 +38,11 @@ use rustc_trait_selection::traits::{
35
38
FulfillmentError , Obligation , ObligationCause , ObligationCauseCode ,
36
39
} ;
37
40
38
- use std:: cmp:: Ordering ;
39
- use std:: iter;
40
-
41
41
use super :: probe:: { AutorefOrPtrAdjustment , IsSuggestion , Mode , ProbeScope } ;
42
42
use super :: { CandidateSource , MethodError , NoMatchData } ;
43
+ use rustc_hir:: intravisit:: Visitor ;
44
+ use std:: cmp:: Ordering ;
45
+ use std:: iter;
43
46
44
47
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
45
48
fn is_fn_ty ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
@@ -1470,6 +1473,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1470
1473
false
1471
1474
}
1472
1475
1476
+ /// For code `rect::area(...)`,
1477
+ /// if `rect` is a local variable and `area` is a valid assoc method for it,
1478
+ /// we try to suggest `rect.area()`
1479
+ pub ( crate ) fn suggest_assoc_method_call ( & self , segs : & [ PathSegment < ' _ > ] ) {
1480
+ debug ! ( "suggest_assoc_method_call segs: {:?}" , segs) ;
1481
+ if segs. len ( ) != 2 {
1482
+ return ;
1483
+ }
1484
+ let ( seg1, seg2) = ( & segs[ 0 ] , & segs[ 1 ] ) ;
1485
+ let Some ( mut diag) =
1486
+ self . tcx . sess . diagnostic ( ) . steal_diagnostic ( seg1. ident . span , StashKey :: CallAssocMethod )
1487
+ else { return } ;
1488
+
1489
+ let map = self . infcx . tcx . hir ( ) ;
1490
+ let body_id = map. body_owned_by ( seg1. hir_id . owner . def_id ) ;
1491
+ let body = map. body ( body_id) ;
1492
+ struct LetVisitor < ' a > {
1493
+ result : Option < & ' a hir:: Expr < ' a > > ,
1494
+ ident_name : Symbol ,
1495
+ }
1496
+
1497
+ impl < ' v > Visitor < ' v > for LetVisitor < ' v > {
1498
+ fn visit_stmt ( & mut self , ex : & ' v hir:: Stmt < ' v > ) {
1499
+ if let hir:: StmtKind :: Local ( hir:: Local { pat, init, .. } ) = & ex. kind {
1500
+ if let Binding ( _, _, ident, ..) = pat. kind &&
1501
+ ident. name == self . ident_name {
1502
+ self . result = * init;
1503
+ }
1504
+ }
1505
+ hir:: intravisit:: walk_stmt ( self , ex) ;
1506
+ }
1507
+ }
1508
+
1509
+ let mut visitor = LetVisitor { result : None , ident_name : seg1. ident . name } ;
1510
+ visitor. visit_body ( & body) ;
1511
+
1512
+ let parent = self . tcx . hir ( ) . get_parent_node ( seg1. hir_id ) ;
1513
+ if let Some ( Node :: Expr ( call_expr) ) = self . tcx . hir ( ) . find ( parent) &&
1514
+ let Some ( expr) = visitor. result {
1515
+ let self_ty = self . check_expr ( expr) ;
1516
+ let probe = self . lookup_probe (
1517
+ seg2. ident ,
1518
+ self_ty,
1519
+ call_expr,
1520
+ ProbeScope :: TraitsInScope ,
1521
+ ) ;
1522
+ if probe. is_ok ( ) {
1523
+ diag. emit ( ) ;
1524
+ return ;
1525
+ }
1526
+ }
1527
+ diag. cancel ( ) ;
1528
+ }
1529
+
1473
1530
/// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
1474
1531
fn suggest_calling_method_on_field (
1475
1532
& self ,
0 commit comments