@@ -6,8 +6,11 @@ use rustc_ast::ast::LitKind;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir:: def_id:: DefIdSet ;
8
8
use rustc_hir:: {
9
- def_id:: DefId , AssocItemKind , BinOpKind , Expr , ExprKind , FnRetTy , ImplItem , ImplItemKind , ImplicitSelfKind , Item ,
10
- ItemKind , Mutability , Node , TraitItemRef , TyKind , UnOp ,
9
+ GenericArg ,
10
+ PathSegment ,
11
+ def:: Res , def_id:: DefId , lang_items:: LangItem , AssocItemKind , BinOpKind , Expr , ExprKind , FnRetTy , GenericBound ,
12
+ ImplItem , ImplItemKind , ImplicitSelfKind , Item , ItemKind , Mutability , Node , PrimTy , QPath , TraitItemRef , TyKind ,
13
+ TypeBindingKind , UnOp ,
11
14
} ;
12
15
use rustc_lint:: { LateContext , LateLintPass } ;
13
16
use rustc_middle:: ty:: { self , AssocKind , FnSig , Ty } ;
@@ -251,12 +254,106 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
251
254
}
252
255
253
256
#[ derive( Debug , Clone , Copy ) ]
254
- enum LenOutput < ' tcx > {
257
+ enum LenOutput {
255
258
Integral ,
256
259
Option ( DefId ) ,
257
- Result ( DefId , Ty < ' tcx > ) ,
260
+ Result ( DefId ) ,
258
261
}
259
- fn parse_len_output < ' tcx > ( cx : & LateContext < ' _ > , sig : FnSig < ' tcx > ) -> Option < LenOutput < ' tcx > > {
262
+
263
+ fn extract_future_output < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Option < & ' tcx PathSegment < ' tcx > > {
264
+ if let ty:: Alias ( _, alias_ty) = ty. kind ( ) {
265
+ let def_id = alias_ty. def_id ;
266
+ let hir_map = cx. tcx . hir ( ) ;
267
+ let item = hir_map. get_if_local ( def_id) ;
268
+ let item = item. unwrap ( ) ;
269
+
270
+ if let Node :: Item ( item) = item {
271
+ if let ItemKind :: OpaqueTy ( opaque) = & item. kind {
272
+ let bounds = opaque. bounds ;
273
+ if bounds. len ( ) != 1 {
274
+ return None ;
275
+ }
276
+ let bound = & bounds[ 0 ] ;
277
+ if let GenericBound :: LangItemTrait ( item, _, _, generic_args) = bound {
278
+ if item != & LangItem :: Future {
279
+ return None ;
280
+ }
281
+
282
+ let bindings = generic_args. bindings ;
283
+ if bindings. len ( ) != 1 {
284
+ return None ;
285
+ }
286
+
287
+ let binding = & bindings[ 0 ] ;
288
+ let kind = & binding. kind ;
289
+
290
+ if let TypeBindingKind :: Equality {
291
+ term : rustc_hir:: Term :: Ty ( term_ty) ,
292
+ } = kind
293
+ {
294
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & term_ty. kind {
295
+ let segments = & path. segments ;
296
+ if segments. len ( ) != 1 {
297
+ return None ;
298
+ }
299
+ let segment = & segments[ 0 ] ;
300
+ return Some ( segment) ;
301
+ }
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+ return None ;
309
+ }
310
+
311
+ fn is_first_generic_integral < ' tcx > ( segment : & ' tcx PathSegment < ' tcx > ) -> bool {
312
+ if let Some ( generic_args) = segment. args {
313
+ if generic_args. args . len ( ) < 1 {
314
+ return false ;
315
+ }
316
+ let arg = & generic_args. args [ 0 ] ;
317
+ if let GenericArg :: Type ( rustc_hir:: Ty { kind, .. } ) = arg {
318
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & kind {
319
+ let segments = & path. segments ;
320
+ let segment = & segments[ 0 ] ;
321
+ let res = & segment. res ;
322
+ if matches ! ( res, Res :: PrimTy ( PrimTy :: Uint ( _) ) ) || matches ! ( res, Res :: PrimTy ( PrimTy :: Int ( _) ) ) {
323
+ return true ;
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ false
330
+ }
331
+
332
+ fn parse_len_output < ' tcx > ( cx : & LateContext < ' tcx > , sig : FnSig < ' tcx > ) -> Option < LenOutput > {
333
+ if let Some ( segment) = extract_future_output ( cx, sig. output ( ) ) {
334
+ let res = segment. res ;
335
+
336
+ if matches ! ( res, Res :: PrimTy ( PrimTy :: Uint ( _) ) ) || matches ! ( res, Res :: PrimTy ( PrimTy :: Int ( _) ) ) {
337
+ return Some ( LenOutput :: Integral ) ;
338
+ }
339
+
340
+ if let Res :: Def ( _, def_id) = res {
341
+ if cx. tcx . is_diagnostic_item ( sym:: Option , def_id) {
342
+ if is_first_generic_integral ( segment) {
343
+ return Some ( LenOutput :: Option ( def_id) ) ;
344
+ }
345
+
346
+ return Some ( LenOutput :: Option ( def_id) ) ;
347
+ } else if cx. tcx . is_diagnostic_item ( sym:: Result , def_id) {
348
+ if is_first_generic_integral ( segment) {
349
+ return Some ( LenOutput :: Option ( def_id) ) ;
350
+ }
351
+ }
352
+ }
353
+
354
+ return None ;
355
+ }
356
+
260
357
match * sig. output ( ) . kind ( ) {
261
358
ty:: Int ( _) | ty:: Uint ( _) => Some ( LenOutput :: Integral ) ,
262
359
ty:: Adt ( adt, subs) if cx. tcx . is_diagnostic_item ( sym:: Option , adt. did ( ) ) => {
@@ -265,19 +362,26 @@ fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenO
265
362
ty:: Adt ( adt, subs) if cx. tcx . is_diagnostic_item ( sym:: Result , adt. did ( ) ) => subs
266
363
. type_at ( 0 )
267
364
. is_integral ( )
268
- . then ( || LenOutput :: Result ( adt. did ( ) , subs . type_at ( 1 ) ) ) ,
365
+ . then ( || LenOutput :: Result ( adt. did ( ) ) ) ,
269
366
_ => None ,
270
367
}
271
368
}
272
369
273
- impl < ' tcx > LenOutput < ' tcx > {
274
- fn matches_is_empty_output ( self , ty : Ty < ' tcx > ) -> bool {
370
+ impl LenOutput {
371
+ fn matches_is_empty_output < ' tcx > ( self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
372
+ if let Some ( segment) = extract_future_output ( cx, ty) {
373
+ return match ( self , segment. res ) {
374
+ ( _, Res :: PrimTy ( PrimTy :: Bool ) ) => true ,
375
+ ( Self :: Option ( _) , Res :: Def ( _, def_id) ) if cx. tcx . is_diagnostic_item ( sym:: Option , def_id) => true ,
376
+ ( Self :: Result ( _) , Res :: Def ( _, def_id) ) if cx. tcx . is_diagnostic_item ( sym:: Result , def_id) => true ,
377
+ _ => false ,
378
+ } ;
379
+ }
380
+
275
381
match ( self , ty. kind ( ) ) {
276
382
( _, & ty:: Bool ) => true ,
277
383
( Self :: Option ( id) , & ty:: Adt ( adt, subs) ) if id == adt. did ( ) => subs. type_at ( 0 ) . is_bool ( ) ,
278
- ( Self :: Result ( id, err_ty) , & ty:: Adt ( adt, subs) ) if id == adt. did ( ) => {
279
- subs. type_at ( 0 ) . is_bool ( ) && subs. type_at ( 1 ) == err_ty
280
- } ,
384
+ ( Self :: Result ( id) , & ty:: Adt ( adt, subs) ) if id == adt. did ( ) => subs. type_at ( 0 ) . is_bool ( ) ,
281
385
_ => false ,
282
386
}
283
387
}
@@ -301,9 +405,14 @@ impl<'tcx> LenOutput<'tcx> {
301
405
}
302
406
303
407
/// Checks if the given signature matches the expectations for `is_empty`
304
- fn check_is_empty_sig < ' tcx > ( sig : FnSig < ' tcx > , self_kind : ImplicitSelfKind , len_output : LenOutput < ' tcx > ) -> bool {
408
+ fn check_is_empty_sig < ' tcx > (
409
+ cx : & LateContext < ' tcx > ,
410
+ sig : FnSig < ' tcx > ,
411
+ self_kind : ImplicitSelfKind ,
412
+ len_output : LenOutput ,
413
+ ) -> bool {
305
414
match & * * sig. inputs_and_output {
306
- [ arg, res] if len_output. matches_is_empty_output ( * res) => {
415
+ [ arg, res] if len_output. matches_is_empty_output ( cx , * res) => {
307
416
matches ! (
308
417
( arg. kind( ) , self_kind) ,
309
418
( ty:: Ref ( _, _, Mutability :: Not ) , ImplicitSelfKind :: ImmRef )
@@ -319,7 +428,7 @@ fn check_for_is_empty<'tcx>(
319
428
cx : & LateContext < ' tcx > ,
320
429
span : Span ,
321
430
self_kind : ImplicitSelfKind ,
322
- output : LenOutput < ' tcx > ,
431
+ output : LenOutput ,
323
432
impl_ty : DefId ,
324
433
item_name : Symbol ,
325
434
item_kind : & str ,
@@ -352,6 +461,7 @@ fn check_for_is_empty<'tcx>(
352
461
Some ( is_empty)
353
462
if !( is_empty. fn_has_self_parameter
354
463
&& check_is_empty_sig (
464
+ cx,
355
465
cx. tcx . fn_sig ( is_empty. def_id ) . subst_identity ( ) . skip_binder ( ) ,
356
466
self_kind,
357
467
output,
0 commit comments