@@ -8,15 +8,14 @@ use rustc_hir as hir;
8
8
use rustc_hir:: def:: { CtorOf , DefKind } ;
9
9
use rustc_hir:: lang_items:: LangItem ;
10
10
use rustc_hir:: {
11
- Expr , ExprKind , GenericBound , ItemKind , Node , Path , QPath , Stmt , StmtKind , TyKind ,
12
- WherePredicate ,
11
+ Expr , ExprKind , GenericBound , Node , Path , QPath , Stmt , StmtKind , TyKind , WherePredicate ,
13
12
} ;
14
13
use rustc_infer:: infer:: { self , TyCtxtInferExt } ;
15
14
use rustc_infer:: traits;
16
15
use rustc_middle:: lint:: in_external_macro;
17
16
use rustc_middle:: ty:: subst:: GenericArgKind ;
18
- use rustc_middle:: ty:: { self , Binder , IsSuggestable , ToPredicate , Ty } ;
19
- use rustc_span:: symbol:: { kw , sym} ;
17
+ use rustc_middle:: ty:: { self , Binder , IsSuggestable , Subst , ToPredicate , Ty } ;
18
+ use rustc_span:: symbol:: sym;
20
19
use rustc_span:: Span ;
21
20
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
22
21
@@ -78,124 +77,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
78
77
expected : Ty < ' tcx > ,
79
78
found : Ty < ' tcx > ,
80
79
) -> bool {
81
- let hir = self . tcx . hir ( ) ;
82
- let ( def_id, sig) = match * found. kind ( ) {
83
- ty:: FnDef ( def_id, _) => ( def_id, found. fn_sig ( self . tcx ) ) ,
84
- ty:: Closure ( def_id, substs) => ( def_id, substs. as_closure ( ) . sig ( ) ) ,
80
+ let ( def_id, output, inputs) = match * found. kind ( ) {
81
+ ty:: FnDef ( def_id, _) => {
82
+ let fn_sig = found. fn_sig ( self . tcx ) ;
83
+ ( def_id, fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) )
84
+ }
85
+ ty:: Closure ( def_id, substs) => {
86
+ let fn_sig = substs. as_closure ( ) . sig ( ) ;
87
+ ( def_id, fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) - 1 )
88
+ }
89
+ ty:: Opaque ( def_id, substs) => {
90
+ let sig = self . tcx . bound_item_bounds ( def_id) . subst ( self . tcx , substs) . iter ( ) . find_map ( |pred| {
91
+ if let ty:: PredicateKind :: Projection ( proj) = pred. kind ( ) . skip_binder ( )
92
+ && Some ( proj. projection_ty . item_def_id ) == self . tcx . lang_items ( ) . fn_once_output ( )
93
+ // args tuple will always be substs[1]
94
+ && let ty:: Tuple ( args) = proj. projection_ty . substs . type_at ( 1 ) . kind ( )
95
+ {
96
+ Some ( (
97
+ pred. kind ( ) . rebind ( proj. term . ty ( ) . unwrap ( ) ) ,
98
+ args. len ( ) ,
99
+ ) )
100
+ } else {
101
+ None
102
+ }
103
+ } ) ;
104
+ if let Some ( ( output, inputs) ) = sig {
105
+ ( def_id, output, inputs)
106
+ } else {
107
+ return false ;
108
+ }
109
+ }
85
110
_ => return false ,
86
111
} ;
87
112
88
- let sig = self . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , sig) ;
89
- let sig = self . normalize_associated_types_in ( expr. span , sig) ;
90
- if self . can_coerce ( sig. output ( ) , expected) {
91
- let ( mut sugg_call, applicability) = if sig. inputs ( ) . is_empty ( ) {
92
- ( String :: new ( ) , Applicability :: MachineApplicable )
93
- } else {
94
- ( "..." . to_string ( ) , Applicability :: HasPlaceholders )
113
+ let output = self . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , output) ;
114
+ let output = self . normalize_associated_types_in ( expr. span , output) ;
115
+ if !output. is_ty_var ( ) && self . can_coerce ( output, expected) {
116
+ let ( sugg_call, mut applicability) = match inputs {
117
+ 0 => ( "" . to_string ( ) , Applicability :: MachineApplicable ) ,
118
+ 1 ..=4 => (
119
+ ( 0 ..inputs) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ,
120
+ Applicability :: MachineApplicable ,
121
+ ) ,
122
+ _ => ( "..." . to_string ( ) , Applicability :: HasPlaceholders ) ,
95
123
} ;
96
- let mut msg = "call this function" ;
97
- match hir. get_if_local ( def_id) {
98
- Some (
99
- Node :: Item ( hir:: Item { kind : ItemKind :: Fn ( .., body_id) , .. } )
100
- | Node :: ImplItem ( hir:: ImplItem {
101
- kind : hir:: ImplItemKind :: Fn ( _, body_id) , ..
102
- } )
103
- | Node :: TraitItem ( hir:: TraitItem {
104
- kind : hir:: TraitItemKind :: Fn ( .., hir:: TraitFn :: Provided ( body_id) ) ,
105
- ..
106
- } ) ,
107
- ) => {
108
- let body = hir. body ( * body_id) ;
109
- sugg_call = body
110
- . params
111
- . iter ( )
112
- . map ( |param| match & param. pat . kind {
113
- hir:: PatKind :: Binding ( _, _, ident, None )
114
- if ident. name != kw:: SelfLower =>
115
- {
116
- ident. to_string ( )
117
- }
118
- _ => "_" . to_string ( ) ,
119
- } )
120
- . collect :: < Vec < _ > > ( )
121
- . join ( ", " ) ;
122
- }
123
- Some ( Node :: Expr ( hir:: Expr {
124
- kind : ExprKind :: Closure { body : body_id, .. } ,
125
- span : full_closure_span,
126
- ..
127
- } ) ) => {
128
- if * full_closure_span == expr. span {
129
- return false ;
130
- }
131
- msg = "call this closure" ;
132
- let body = hir. body ( * body_id) ;
133
- sugg_call = body
134
- . params
135
- . iter ( )
136
- . map ( |param| match & param. pat . kind {
137
- hir:: PatKind :: Binding ( _, _, ident, None )
138
- if ident. name != kw:: SelfLower =>
139
- {
140
- ident. to_string ( )
141
- }
142
- _ => "_" . to_string ( ) ,
143
- } )
144
- . collect :: < Vec < _ > > ( )
145
- . join ( ", " ) ;
146
- }
147
- Some ( Node :: Ctor ( hir:: VariantData :: Tuple ( fields, _) ) ) => {
148
- sugg_call = fields. iter ( ) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
149
- match def_id. as_local ( ) . map ( |def_id| self . tcx . def_kind ( def_id) ) {
150
- Some ( DefKind :: Ctor ( hir:: def:: CtorOf :: Variant , _) ) => {
151
- msg = "instantiate this tuple variant" ;
152
- }
153
- Some ( DefKind :: Ctor ( CtorOf :: Struct , _) ) => {
154
- msg = "instantiate this tuple struct" ;
155
- }
156
- _ => { }
157
- }
124
+
125
+ let msg = match self . tcx . def_kind ( def_id) {
126
+ DefKind :: Fn => "call this function" ,
127
+ DefKind :: Closure | DefKind :: OpaqueTy => "call this closure" ,
128
+ DefKind :: Ctor ( CtorOf :: Struct , _) => "instantiate this tuple struct" ,
129
+ DefKind :: Ctor ( CtorOf :: Variant , _) => "instantiate this tuple variant" ,
130
+ _ => "call this function" ,
131
+ } ;
132
+
133
+ let sugg = match expr. kind {
134
+ hir:: ExprKind :: Call ( ..)
135
+ | hir:: ExprKind :: Path ( ..)
136
+ | hir:: ExprKind :: Index ( ..)
137
+ | hir:: ExprKind :: Lit ( ..) => {
138
+ vec ! [ ( expr. span. shrink_to_hi( ) , format!( "({sugg_call})" ) ) ]
158
139
}
159
- Some ( Node :: ForeignItem ( hir:: ForeignItem {
160
- kind : hir:: ForeignItemKind :: Fn ( _, idents, _) ,
161
- ..
162
- } ) ) => {
163
- sugg_call = idents
164
- . iter ( )
165
- . map ( |ident| {
166
- if ident. name != kw:: SelfLower {
167
- ident. to_string ( )
168
- } else {
169
- "_" . to_string ( )
170
- }
171
- } )
172
- . collect :: < Vec < _ > > ( )
173
- . join ( ", " )
140
+ hir:: ExprKind :: Closure { .. } => {
141
+ // Might be `{ expr } || { bool }`
142
+ applicability = Applicability :: MaybeIncorrect ;
143
+ vec ! [
144
+ ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
145
+ ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
146
+ ]
174
147
}
175
- Some ( Node :: TraitItem ( hir:: TraitItem {
176
- kind : hir:: TraitItemKind :: Fn ( .., hir:: TraitFn :: Required ( idents) ) ,
177
- ..
178
- } ) ) => {
179
- sugg_call = idents
180
- . iter ( )
181
- . map ( |ident| {
182
- if ident. name != kw:: SelfLower {
183
- ident. to_string ( )
184
- } else {
185
- "_" . to_string ( )
186
- }
187
- } )
188
- . collect :: < Vec < _ > > ( )
189
- . join ( ", " )
148
+ _ => {
149
+ vec ! [
150
+ ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
151
+ ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
152
+ ]
190
153
}
191
- _ => { }
192
- }
193
- err. span_suggestion_verbose (
194
- expr. span . shrink_to_hi ( ) ,
195
- & format ! ( "use parentheses to {}" , msg) ,
196
- format ! ( "({})" , sugg_call) ,
154
+ } ;
155
+
156
+ err. multipart_suggestion_verbose (
157
+ format ! ( "use parentheses to {msg}" ) ,
158
+ sugg,
197
159
applicability,
198
160
) ;
161
+
199
162
return true ;
200
163
}
201
164
false
0 commit comments