@@ -81,9 +81,8 @@ impl ExprValidator {
81
81
}
82
82
83
83
fn validate_body ( & mut self , db : & dyn HirDatabase ) {
84
- self . check_for_filter_map_next ( db) ;
85
-
86
84
let body = db. body ( self . owner ) ;
85
+ let mut filter_map_next_checker = None ;
87
86
88
87
for ( id, expr) in body. exprs . iter ( ) {
89
88
if let Some ( ( variant, missed_fields, true ) ) =
@@ -101,7 +100,7 @@ impl ExprValidator {
101
100
self . validate_match ( id, * expr, arms, db, self . infer . clone ( ) ) ;
102
101
}
103
102
Expr :: Call { .. } | Expr :: MethodCall { .. } => {
104
- self . validate_call ( db, id, expr) ;
103
+ self . validate_call ( db, id, expr, & mut filter_map_next_checker ) ;
105
104
}
106
105
_ => { }
107
106
}
@@ -143,58 +142,13 @@ impl ExprValidator {
143
142
} ) ;
144
143
}
145
144
146
- fn check_for_filter_map_next ( & mut self , db : & dyn HirDatabase ) {
147
- // Find the FunctionIds for Iterator::filter_map and Iterator::next
148
- let iterator_path = path ! [ core:: iter:: Iterator ] ;
149
- let resolver = self . owner . resolver ( db. upcast ( ) ) ;
150
- let iterator_trait_id = match resolver. resolve_known_trait ( db. upcast ( ) , & iterator_path) {
151
- Some ( id) => id,
152
- None => return ,
153
- } ;
154
- let iterator_trait_items = & db. trait_data ( iterator_trait_id) . items ;
155
- let filter_map_function_id =
156
- match iterator_trait_items. iter ( ) . find ( |item| item. 0 == name ! [ filter_map] ) {
157
- Some ( ( _, AssocItemId :: FunctionId ( id) ) ) => id,
158
- _ => return ,
159
- } ;
160
- let next_function_id = match iterator_trait_items. iter ( ) . find ( |item| item. 0 == name ! [ next] )
161
- {
162
- Some ( ( _, AssocItemId :: FunctionId ( id) ) ) => id,
163
- _ => return ,
164
- } ;
165
-
166
- // Search function body for instances of .filter_map(..).next()
167
- let body = db. body ( self . owner ) ;
168
- let mut prev = None ;
169
- for ( id, expr) in body. exprs . iter ( ) {
170
- if let Expr :: MethodCall { receiver, .. } = expr {
171
- let function_id = match self . infer . method_resolution ( id) {
172
- Some ( ( id, _) ) => id,
173
- None => continue ,
174
- } ;
175
-
176
- if function_id == * filter_map_function_id {
177
- prev = Some ( id) ;
178
- continue ;
179
- }
180
-
181
- if function_id == * next_function_id {
182
- if let Some ( filter_map_id) = prev {
183
- if * receiver == filter_map_id {
184
- self . diagnostics . push (
185
- BodyValidationDiagnostic :: ReplaceFilterMapNextWithFindMap {
186
- method_call_expr : id,
187
- } ,
188
- ) ;
189
- }
190
- }
191
- }
192
- }
193
- prev = None ;
194
- }
195
- }
196
-
197
- fn validate_call ( & mut self , db : & dyn HirDatabase , call_id : ExprId , expr : & Expr ) {
145
+ fn validate_call (
146
+ & mut self ,
147
+ db : & dyn HirDatabase ,
148
+ call_id : ExprId ,
149
+ expr : & Expr ,
150
+ filter_map_next_checker : & mut Option < FilterMapNextChecker > ,
151
+ ) {
198
152
// Check that the number of arguments matches the number of parameters.
199
153
200
154
// FIXME: Due to shortcomings in the current type system implementation, only emit this
@@ -214,6 +168,24 @@ impl ExprValidator {
214
168
( sig, args. len ( ) )
215
169
}
216
170
Expr :: MethodCall { receiver, args, .. } => {
171
+ let ( callee, subst) = match self . infer . method_resolution ( call_id) {
172
+ Some ( it) => it,
173
+ None => return ,
174
+ } ;
175
+
176
+ if filter_map_next_checker
177
+ . get_or_insert_with ( || {
178
+ FilterMapNextChecker :: new ( & self . owner . resolver ( db. upcast ( ) ) , db)
179
+ } )
180
+ . check ( call_id, receiver, & callee)
181
+ . is_some ( )
182
+ {
183
+ self . diagnostics . push (
184
+ BodyValidationDiagnostic :: ReplaceFilterMapNextWithFindMap {
185
+ method_call_expr : call_id,
186
+ } ,
187
+ ) ;
188
+ }
217
189
let receiver = & self . infer . type_of_expr [ * receiver] ;
218
190
if receiver. strip_references ( ) . is_unknown ( ) {
219
191
// if the receiver is of unknown type, it's very likely we
@@ -222,10 +194,6 @@ impl ExprValidator {
222
194
return ;
223
195
}
224
196
225
- let ( callee, subst) = match self . infer . method_resolution ( call_id) {
226
- Some ( it) => it,
227
- None => return ,
228
- } ;
229
197
let sig = db. callable_item_signature ( callee. into ( ) ) . substitute ( Interner , & subst) ;
230
198
231
199
( sig, args. len ( ) + 1 )
@@ -424,6 +392,63 @@ impl ExprValidator {
424
392
}
425
393
}
426
394
395
+ struct FilterMapNextChecker {
396
+ filter_map_function_id : Option < hir_def:: FunctionId > ,
397
+ next_function_id : Option < hir_def:: FunctionId > ,
398
+ prev_filter_map_expr_id : Option < ExprId > ,
399
+ }
400
+
401
+ impl FilterMapNextChecker {
402
+ fn new ( resolver : & hir_def:: resolver:: Resolver , db : & dyn HirDatabase ) -> Self {
403
+ // Find and store the FunctionIds for Iterator::filter_map and Iterator::next
404
+ let iterator_path = path ! [ core:: iter:: Iterator ] ;
405
+ let mut filter_map_function_id = None ;
406
+ let mut next_function_id = None ;
407
+
408
+ if let Some ( iterator_trait_id) = resolver. resolve_known_trait ( db. upcast ( ) , & iterator_path) {
409
+ let iterator_trait_items = & db. trait_data ( iterator_trait_id) . items ;
410
+ for item in iterator_trait_items. iter ( ) {
411
+ if let ( name, AssocItemId :: FunctionId ( id) ) = item {
412
+ if * name == name ! [ filter_map] {
413
+ filter_map_function_id = Some ( * id) ;
414
+ }
415
+ if * name == name ! [ next] {
416
+ next_function_id = Some ( * id) ;
417
+ }
418
+ }
419
+ if filter_map_function_id. is_some ( ) && next_function_id. is_some ( ) {
420
+ break ;
421
+ }
422
+ }
423
+ }
424
+ Self { filter_map_function_id, next_function_id, prev_filter_map_expr_id : None }
425
+ }
426
+
427
+ // check for instances of .filter_map(..).next()
428
+ fn check (
429
+ & mut self ,
430
+ current_expr_id : ExprId ,
431
+ receiver_expr_id : & ExprId ,
432
+ function_id : & hir_def:: FunctionId ,
433
+ ) -> Option < ( ) > {
434
+ if * function_id == self . filter_map_function_id ? {
435
+ self . prev_filter_map_expr_id = Some ( current_expr_id) ;
436
+ return None ;
437
+ }
438
+
439
+ if * function_id == self . next_function_id ? {
440
+ if let Some ( prev_filter_map_expr_id) = self . prev_filter_map_expr_id {
441
+ if * receiver_expr_id == prev_filter_map_expr_id {
442
+ return Some ( ( ) ) ;
443
+ }
444
+ }
445
+ }
446
+
447
+ self . prev_filter_map_expr_id = None ;
448
+ None
449
+ }
450
+ }
451
+
427
452
pub fn record_literal_missing_fields (
428
453
db : & dyn HirDatabase ,
429
454
infer : & InferenceResult ,
0 commit comments