@@ -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 , UnOp ,
9
+ def:: Res , def_id:: DefId , lang_items:: LangItem , AssocItemKind , BinOpKind , Expr , ExprKind , FnRetTy , GenericBound ,
10
+ ImplItem , ImplItemKind , ImplicitSelfKind , Item , ItemKind , Mutability , Node , PrimTy , QPath , TraitItemRef , TyKind ,
11
+ TypeBindingKind , UnOp ,
11
12
} ;
12
13
use rustc_lint:: { LateContext , LateLintPass } ;
13
14
use rustc_middle:: ty:: { self , AssocKind , FnSig , Ty } ;
@@ -256,7 +257,84 @@ enum LenOutput<'tcx> {
256
257
Option ( DefId ) ,
257
258
Result ( DefId , Ty < ' tcx > ) ,
258
259
}
259
- fn parse_len_output < ' tcx > ( cx : & LateContext < ' _ > , sig : FnSig < ' tcx > ) -> Option < LenOutput < ' tcx > > {
260
+
261
+ fn extract_future_output < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Option < Res > {
262
+ if let ty:: Alias ( _, alias_ty) = ty. kind ( ) {
263
+ let def_id = alias_ty. def_id ;
264
+ let hir_map = cx. tcx . hir ( ) ;
265
+ let item = hir_map. get_if_local ( def_id) ;
266
+ let item = item. unwrap ( ) ;
267
+
268
+ if let Node :: Item ( item) = item {
269
+ if let ItemKind :: OpaqueTy ( opaque) = & item. kind {
270
+ let bounds = opaque. bounds ;
271
+ let bound = & bounds[ 0 ] ;
272
+ if let GenericBound :: LangItemTrait ( item, _, _, generic_args) = bound {
273
+ if item != & LangItem :: Future {
274
+ return None ;
275
+ }
276
+
277
+ let bindings = generic_args. bindings ;
278
+ if bindings. len ( ) != 1 {
279
+ return None ;
280
+ }
281
+
282
+ let binding = & bindings[ 0 ] ;
283
+ let kind = & binding. kind ;
284
+
285
+ if let TypeBindingKind :: Equality {
286
+ term : rustc_hir:: Term :: Ty ( term_ty) ,
287
+ } = kind
288
+ {
289
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & term_ty. kind {
290
+ let segments = & path. segments ;
291
+ let segment = & segments[ 0 ] ;
292
+ let res = segment. res ;
293
+
294
+ return Some ( res) ;
295
+ }
296
+ }
297
+ }
298
+ }
299
+ }
300
+ }
301
+
302
+ return None ;
303
+ }
304
+
305
+ // fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
306
+ // if_chain! {
307
+ // if let Some(segment) = trait_ref.path.segments.last();
308
+ // if let Some(args) = segment.args;
309
+ // if args.bindings.len() == 1;
310
+ // let binding = &args.bindings[0];
311
+ // if binding.ident.name == sym::Output;
312
+ // if let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind;
313
+ // then {
314
+ // return Some(output);
315
+ // }
316
+ // }
317
+
318
+ // None
319
+ // }
320
+
321
+ fn parse_len_output < ' tcx > ( cx : & LateContext < ' tcx > , sig : FnSig < ' tcx > ) -> Option < LenOutput < ' tcx > > {
322
+ if let Some ( res) = extract_future_output ( cx, sig. output ( ) ) {
323
+ if matches ! ( res, Res :: PrimTy ( PrimTy :: Uint ( _) ) ) || matches ! ( res, Res :: PrimTy ( PrimTy :: Int ( _) ) ) {
324
+ return Some ( LenOutput :: Integral ) ;
325
+ }
326
+
327
+ if let Res :: Def ( _, def_id) = res {
328
+ if cx. tcx . is_diagnostic_item ( sym:: Option , def_id) {
329
+ return Some ( LenOutput :: Option ( def_id) ) ;
330
+ } else if cx. tcx . is_diagnostic_item ( sym:: Result , def_id) {
331
+ return Some ( LenOutput :: Result ( def_id, cx. tcx . ty_error ( ) ) ) ;
332
+ }
333
+ }
334
+
335
+ panic ! ( ) ;
336
+ }
337
+
260
338
match * sig. output ( ) . kind ( ) {
261
339
ty:: Int ( _) | ty:: Uint ( _) => Some ( LenOutput :: Integral ) ,
262
340
ty:: Adt ( adt, subs) if cx. tcx . is_diagnostic_item ( sym:: Option , adt. did ( ) ) => {
@@ -271,7 +349,16 @@ fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenO
271
349
}
272
350
273
351
impl < ' tcx > LenOutput < ' tcx > {
274
- fn matches_is_empty_output ( self , ty : Ty < ' tcx > ) -> bool {
352
+ fn matches_is_empty_output ( self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
353
+ if let Some ( future_output) = extract_future_output ( cx, ty) {
354
+ return match ( self , future_output) {
355
+ ( _, Res :: PrimTy ( PrimTy :: Bool ) ) => true ,
356
+ ( Self :: Option ( _) , Res :: Def ( _, def_id) ) if cx. tcx . is_diagnostic_item ( sym:: Option , def_id) => true ,
357
+ ( Self :: Result ( _, _) , Res :: Def ( _, def_id) ) if cx. tcx . is_diagnostic_item ( sym:: Result , def_id) => true ,
358
+ _ => false ,
359
+ } ;
360
+ }
361
+
275
362
match ( self , ty. kind ( ) ) {
276
363
( _, & ty:: Bool ) => true ,
277
364
( Self :: Option ( id) , & ty:: Adt ( adt, subs) ) if id == adt. did ( ) => subs. type_at ( 0 ) . is_bool ( ) ,
@@ -301,9 +388,14 @@ impl<'tcx> LenOutput<'tcx> {
301
388
}
302
389
303
390
/// 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 {
391
+ fn check_is_empty_sig < ' tcx > (
392
+ cx : & LateContext < ' tcx > ,
393
+ sig : FnSig < ' tcx > ,
394
+ self_kind : ImplicitSelfKind ,
395
+ len_output : LenOutput < ' tcx > ,
396
+ ) -> bool {
305
397
match & * * sig. inputs_and_output {
306
- [ arg, res] if len_output. matches_is_empty_output ( * res) => {
398
+ [ arg, res] if len_output. matches_is_empty_output ( cx , * res) => {
307
399
matches ! (
308
400
( arg. kind( ) , self_kind) ,
309
401
( ty:: Ref ( _, _, Mutability :: Not ) , ImplicitSelfKind :: ImmRef )
@@ -352,6 +444,7 @@ fn check_for_is_empty<'tcx>(
352
444
Some ( is_empty)
353
445
if !( is_empty. fn_has_self_parameter
354
446
&& check_is_empty_sig (
447
+ cx,
355
448
cx. tcx . fn_sig ( is_empty. def_id ) . subst_identity ( ) . skip_binder ( ) ,
356
449
self_kind,
357
450
output,
0 commit comments