@@ -6,8 +6,9 @@ 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 ,
9
+ def:: Res , def_id:: DefId , lang_items:: LangItem , AssocItemKind , BinOpKind , Expr , ExprKind , FnRetTy , GenericArg ,
10
+ GenericBound , ImplItem , ImplItemKind , ImplicitSelfKind , Item , ItemKind , Mutability , Node , PathSegment , PrimTy ,
11
+ QPath , TraitItemRef , TyKind , TypeBindingKind ,
11
12
} ;
12
13
use rustc_lint:: { LateContext , LateLintPass } ;
13
14
use rustc_middle:: ty:: { self , AssocKind , FnSig , Ty } ;
@@ -250,33 +251,98 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
250
251
}
251
252
252
253
#[ derive( Debug , Clone , Copy ) ]
253
- enum LenOutput < ' tcx > {
254
+ enum LenOutput {
254
255
Integral ,
255
256
Option ( DefId ) ,
256
- Result ( DefId , Ty < ' tcx > ) ,
257
+ Result ( DefId ) ,
257
258
}
258
- fn parse_len_output < ' tcx > ( cx : & LateContext < ' _ > , sig : FnSig < ' tcx > ) -> Option < LenOutput < ' tcx > > {
259
+
260
+ fn extract_future_output < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Option < & ' tcx PathSegment < ' tcx > > {
261
+ if let ty:: Alias ( _, alias_ty) = ty. kind ( ) &&
262
+ let Some ( Node :: Item ( item) ) = cx. tcx . hir ( ) . get_if_local ( alias_ty. def_id ) &&
263
+ let Item { kind : ItemKind :: OpaqueTy ( opaque) , .. } = item &&
264
+ opaque. bounds . len ( ) == 1 &&
265
+ let GenericBound :: LangItemTrait ( LangItem :: Future , _, _, generic_args) = & opaque. bounds [ 0 ] &&
266
+ generic_args. bindings . len ( ) == 1 &&
267
+ let TypeBindingKind :: Equality {
268
+ term : rustc_hir:: Term :: Ty ( rustc_hir:: Ty { kind : TyKind :: Path ( QPath :: Resolved ( _, path) ) , .. } ) ,
269
+ } = & generic_args. bindings [ 0 ] . kind &&
270
+ path. segments . len ( ) == 1 {
271
+ return Some ( & path. segments [ 0 ] ) ;
272
+ }
273
+
274
+ None
275
+ }
276
+
277
+ fn is_first_generic_integral < ' tcx > ( segment : & ' tcx PathSegment < ' tcx > ) -> bool {
278
+ if let Some ( generic_args) = segment. args {
279
+ if generic_args. args . is_empty ( ) {
280
+ return false ;
281
+ }
282
+ let arg = & generic_args. args [ 0 ] ;
283
+ if let GenericArg :: Type ( rustc_hir:: Ty {
284
+ kind : TyKind :: Path ( QPath :: Resolved ( _, path) ) ,
285
+ ..
286
+ } ) = arg
287
+ {
288
+ let segments = & path. segments ;
289
+ let segment = & segments[ 0 ] ;
290
+ let res = & segment. res ;
291
+ if matches ! ( res, Res :: PrimTy ( PrimTy :: Uint ( _) ) ) || matches ! ( res, Res :: PrimTy ( PrimTy :: Int ( _) ) ) {
292
+ return true ;
293
+ }
294
+ }
295
+ }
296
+
297
+ false
298
+ }
299
+
300
+ fn parse_len_output < ' tcx > ( cx : & LateContext < ' tcx > , sig : FnSig < ' tcx > ) -> Option < LenOutput > {
301
+ if let Some ( segment) = extract_future_output ( cx, sig. output ( ) ) {
302
+ let res = segment. res ;
303
+
304
+ if matches ! ( res, Res :: PrimTy ( PrimTy :: Uint ( _) ) ) || matches ! ( res, Res :: PrimTy ( PrimTy :: Int ( _) ) ) {
305
+ return Some ( LenOutput :: Integral ) ;
306
+ }
307
+
308
+ if let Res :: Def ( _, def_id) = res {
309
+ if cx. tcx . is_diagnostic_item ( sym:: Option , def_id) && is_first_generic_integral ( segment) {
310
+ return Some ( LenOutput :: Option ( def_id) ) ;
311
+ } else if cx. tcx . is_diagnostic_item ( sym:: Result , def_id) && is_first_generic_integral ( segment) {
312
+ return Some ( LenOutput :: Result ( def_id) ) ;
313
+ }
314
+ }
315
+
316
+ return None ;
317
+ }
318
+
259
319
match * sig. output ( ) . kind ( ) {
260
320
ty:: Int ( _) | ty:: Uint ( _) => Some ( LenOutput :: Integral ) ,
261
321
ty:: Adt ( adt, subs) if cx. tcx . is_diagnostic_item ( sym:: Option , adt. did ( ) ) => {
262
322
subs. type_at ( 0 ) . is_integral ( ) . then ( || LenOutput :: Option ( adt. did ( ) ) )
263
323
} ,
264
- ty:: Adt ( adt, subs) if cx. tcx . is_diagnostic_item ( sym:: Result , adt. did ( ) ) => subs
265
- . type_at ( 0 )
266
- . is_integral ( )
267
- . then ( || LenOutput :: Result ( adt. did ( ) , subs. type_at ( 1 ) ) ) ,
324
+ ty:: Adt ( adt, subs) if cx. tcx . is_diagnostic_item ( sym:: Result , adt. did ( ) ) => {
325
+ subs. type_at ( 0 ) . is_integral ( ) . then ( || LenOutput :: Result ( adt. did ( ) ) )
326
+ } ,
268
327
_ => None ,
269
328
}
270
329
}
271
330
272
- impl < ' tcx > LenOutput < ' tcx > {
273
- fn matches_is_empty_output ( self , ty : Ty < ' tcx > ) -> bool {
331
+ impl LenOutput {
332
+ fn matches_is_empty_output < ' tcx > ( self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
333
+ if let Some ( segment) = extract_future_output ( cx, ty) {
334
+ return match ( self , segment. res ) {
335
+ ( _, Res :: PrimTy ( PrimTy :: Bool ) ) => true ,
336
+ ( Self :: Option ( _) , Res :: Def ( _, def_id) ) if cx. tcx . is_diagnostic_item ( sym:: Option , def_id) => true ,
337
+ ( Self :: Result ( _) , Res :: Def ( _, def_id) ) if cx. tcx . is_diagnostic_item ( sym:: Result , def_id) => true ,
338
+ _ => false ,
339
+ } ;
340
+ }
341
+
274
342
match ( self , ty. kind ( ) ) {
275
343
( _, & ty:: Bool ) => true ,
276
344
( Self :: Option ( id) , & ty:: Adt ( adt, subs) ) if id == adt. did ( ) => subs. type_at ( 0 ) . is_bool ( ) ,
277
- ( Self :: Result ( id, err_ty) , & ty:: Adt ( adt, subs) ) if id == adt. did ( ) => {
278
- subs. type_at ( 0 ) . is_bool ( ) && subs. type_at ( 1 ) == err_ty
279
- } ,
345
+ ( Self :: Result ( id) , & ty:: Adt ( adt, subs) ) if id == adt. did ( ) => subs. type_at ( 0 ) . is_bool ( ) ,
280
346
_ => false ,
281
347
}
282
348
}
@@ -300,9 +366,14 @@ impl<'tcx> LenOutput<'tcx> {
300
366
}
301
367
302
368
/// Checks if the given signature matches the expectations for `is_empty`
303
- fn check_is_empty_sig < ' tcx > ( sig : FnSig < ' tcx > , self_kind : ImplicitSelfKind , len_output : LenOutput < ' tcx > ) -> bool {
369
+ fn check_is_empty_sig < ' tcx > (
370
+ cx : & LateContext < ' tcx > ,
371
+ sig : FnSig < ' tcx > ,
372
+ self_kind : ImplicitSelfKind ,
373
+ len_output : LenOutput ,
374
+ ) -> bool {
304
375
match & * * sig. inputs_and_output {
305
- [ arg, res] if len_output. matches_is_empty_output ( * res) => {
376
+ [ arg, res] if len_output. matches_is_empty_output ( cx , * res) => {
306
377
matches ! (
307
378
( arg. kind( ) , self_kind) ,
308
379
( ty:: Ref ( _, _, Mutability :: Not ) , ImplicitSelfKind :: ImmRef )
@@ -314,11 +385,11 @@ fn check_is_empty_sig<'tcx>(sig: FnSig<'tcx>, self_kind: ImplicitSelfKind, len_o
314
385
}
315
386
316
387
/// Checks if the given type has an `is_empty` method with the appropriate signature.
317
- fn check_for_is_empty < ' tcx > (
318
- cx : & LateContext < ' tcx > ,
388
+ fn check_for_is_empty (
389
+ cx : & LateContext < ' _ > ,
319
390
span : Span ,
320
391
self_kind : ImplicitSelfKind ,
321
- output : LenOutput < ' tcx > ,
392
+ output : LenOutput ,
322
393
impl_ty : DefId ,
323
394
item_name : Symbol ,
324
395
item_kind : & str ,
@@ -351,6 +422,7 @@ fn check_for_is_empty<'tcx>(
351
422
Some ( is_empty)
352
423
if !( is_empty. fn_has_self_parameter
353
424
&& check_is_empty_sig (
425
+ cx,
354
426
cx. tcx . fn_sig ( is_empty. def_id ) . subst_identity ( ) . skip_binder ( ) ,
355
427
self_kind,
356
428
output,
0 commit comments