@@ -14,8 +14,8 @@ use rustc_lint::LateContext;
14
14
use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
15
15
use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
16
16
use rustc_middle:: ty:: {
17
- self , AdtDef , Binder , BoundRegion , FnSig , IntTy , ParamEnv , Predicate , PredicateKind , Region , RegionKind , Ty ,
18
- TyCtxt , TypeFoldable , TypeSuperFoldable , TypeVisitor , UintTy , VariantDiscr ,
17
+ self , AdtDef , Binder , BoundRegion , FnSig , IntTy , ParamEnv , Predicate , PredicateKind , ProjectionTy , Region ,
18
+ RegionKind , Ty , TyCtxt , TypeFoldable , TypeSuperFoldable , TypeVisitor , UintTy , VariantDiscr ,
19
19
} ;
20
20
use rustc_span:: symbol:: Ident ;
21
21
use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
@@ -530,74 +530,118 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
530
530
if let Res :: Def ( DefKind :: Fn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: AssocFn , id) = path_res ( cx, expr) {
531
531
Some ( ExprFnSig :: Sig ( cx. tcx . fn_sig ( id) ) )
532
532
} else {
533
- let ty = cx. typeck_results ( ) . expr_ty_adjusted ( expr) . peel_refs ( ) ;
534
- match * ty. kind ( ) {
535
- ty:: Closure ( _, subs) => Some ( ExprFnSig :: Closure ( subs. as_closure ( ) . sig ( ) ) ) ,
536
- ty:: FnDef ( id, subs) => Some ( ExprFnSig :: Sig ( cx. tcx . bound_fn_sig ( id) . subst ( cx. tcx , subs) ) ) ,
537
- ty:: FnPtr ( sig) => Some ( ExprFnSig :: Sig ( sig) ) ,
538
- ty:: Dynamic ( bounds, _) => {
539
- let lang_items = cx. tcx . lang_items ( ) ;
540
- match bounds. principal ( ) {
541
- Some ( bound)
542
- if Some ( bound. def_id ( ) ) == lang_items. fn_trait ( )
543
- || Some ( bound. def_id ( ) ) == lang_items. fn_once_trait ( )
544
- || Some ( bound. def_id ( ) ) == lang_items. fn_mut_trait ( ) =>
545
- {
546
- let output = bounds
547
- . projection_bounds ( )
548
- . find ( |p| lang_items. fn_once_output ( ) . map_or ( false , |id| id == p. item_def_id ( ) ) )
549
- . map ( |p| p. map_bound ( |p| p. term . ty ( ) . expect ( "return type was a const" ) ) ) ;
550
- Some ( ExprFnSig :: Trait ( bound. map_bound ( |b| b. substs . type_at ( 0 ) ) , output) )
551
- } ,
552
- _ => None ,
533
+ ty_sig ( cx, cx. typeck_results ( ) . expr_ty_adjusted ( expr) . peel_refs ( ) )
534
+ }
535
+ }
536
+
537
+ fn ty_sig < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Option < ExprFnSig < ' tcx > > {
538
+ match * ty. kind ( ) {
539
+ ty:: Closure ( _, subs) => Some ( ExprFnSig :: Closure ( subs. as_closure ( ) . sig ( ) ) ) ,
540
+ ty:: FnDef ( id, subs) => Some ( ExprFnSig :: Sig ( cx. tcx . bound_fn_sig ( id) . subst ( cx. tcx , subs) ) ) ,
541
+ ty:: FnPtr ( sig) => Some ( ExprFnSig :: Sig ( sig) ) ,
542
+ ty:: Dynamic ( bounds, _) => {
543
+ let lang_items = cx. tcx . lang_items ( ) ;
544
+ match bounds. principal ( ) {
545
+ Some ( bound)
546
+ if Some ( bound. def_id ( ) ) == lang_items. fn_trait ( )
547
+ || Some ( bound. def_id ( ) ) == lang_items. fn_once_trait ( )
548
+ || Some ( bound. def_id ( ) ) == lang_items. fn_mut_trait ( ) =>
549
+ {
550
+ let output = bounds
551
+ . projection_bounds ( )
552
+ . find ( |p| lang_items. fn_once_output ( ) . map_or ( false , |id| id == p. item_def_id ( ) ) )
553
+ . map ( |p| p. map_bound ( |p| p. term . ty ( ) . unwrap ( ) ) ) ;
554
+ Some ( ExprFnSig :: Trait ( bound. map_bound ( |b| b. substs . type_at ( 0 ) ) , output) )
555
+ } ,
556
+ _ => None ,
557
+ }
558
+ } ,
559
+ ty:: Projection ( proj) => match cx. tcx . try_normalize_erasing_regions ( cx. param_env , ty) {
560
+ Ok ( normalized_ty) if normalized_ty != ty => ty_sig ( cx, normalized_ty) ,
561
+ _ => sig_for_projection ( cx, proj) . or_else ( || sig_from_bounds ( cx, ty) ) ,
562
+ } ,
563
+ ty:: Param ( _) => sig_from_bounds ( cx, ty) ,
564
+ _ => None ,
565
+ }
566
+ }
567
+
568
+ fn sig_from_bounds < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Option < ExprFnSig < ' tcx > > {
569
+ let mut inputs = None ;
570
+ let mut output = None ;
571
+ let lang_items = cx. tcx . lang_items ( ) ;
572
+
573
+ for ( pred, _) in all_predicates_of ( cx. tcx , cx. typeck_results ( ) . hir_owner . to_def_id ( ) ) {
574
+ match pred. kind ( ) . skip_binder ( ) {
575
+ PredicateKind :: Trait ( p)
576
+ if ( lang_items. fn_trait ( ) == Some ( p. def_id ( ) )
577
+ || lang_items. fn_mut_trait ( ) == Some ( p. def_id ( ) )
578
+ || lang_items. fn_once_trait ( ) == Some ( p. def_id ( ) ) )
579
+ && p. self_ty ( ) == ty =>
580
+ {
581
+ if inputs. is_some ( ) {
582
+ // Multiple different fn trait impls. Is this even allowed?
583
+ return None ;
553
584
}
585
+ inputs = Some ( pred. kind ( ) . rebind ( p. trait_ref . substs . type_at ( 1 ) ) ) ;
554
586
} ,
555
- ty:: Param ( _) | ty:: Projection ( ..) => {
556
- let mut inputs = None ;
557
- let mut output = None ;
558
- let lang_items = cx. tcx . lang_items ( ) ;
559
-
560
- for ( pred, _) in all_predicates_of ( cx. tcx , cx. typeck_results ( ) . hir_owner . to_def_id ( ) ) {
561
- let mut is_input = false ;
562
- if let Some ( ty) = pred
563
- . kind ( )
564
- . map_bound ( |pred| match pred {
565
- PredicateKind :: Trait ( p)
566
- if ( lang_items. fn_trait ( ) == Some ( p. def_id ( ) )
567
- || lang_items. fn_mut_trait ( ) == Some ( p. def_id ( ) )
568
- || lang_items. fn_once_trait ( ) == Some ( p. def_id ( ) ) )
569
- && p. self_ty ( ) == ty =>
570
- {
571
- is_input = true ;
572
- Some ( p. trait_ref . substs . type_at ( 1 ) )
573
- } ,
574
- PredicateKind :: Projection ( p)
575
- if Some ( p. projection_ty . item_def_id ) == lang_items. fn_once_output ( )
576
- && p. projection_ty . self_ty ( ) == ty =>
577
- {
578
- is_input = false ;
579
- p. term . ty ( )
580
- } ,
581
- _ => None ,
582
- } )
583
- . transpose ( )
584
- {
585
- if is_input && inputs. is_none ( ) {
586
- inputs = Some ( ty) ;
587
- } else if !is_input && output. is_none ( ) {
588
- output = Some ( ty) ;
589
- } else {
590
- // Multiple different fn trait impls. Is this even allowed?
591
- return None ;
592
- }
593
- }
587
+ PredicateKind :: Projection ( p)
588
+ if Some ( p. projection_ty . item_def_id ) == lang_items. fn_once_output ( )
589
+ && p. projection_ty . self_ty ( ) == ty =>
590
+ {
591
+ if output. is_some ( ) {
592
+ // Multiple different fn trait impls. Is this even allowed?
593
+ return None ;
594
594
}
595
+ output = Some ( pred. kind ( ) . rebind ( p. term . ty ( ) . unwrap ( ) ) ) ;
596
+ } ,
597
+ _ => ( ) ,
598
+ }
599
+ }
600
+
601
+ inputs. map ( |ty| ExprFnSig :: Trait ( ty, output) )
602
+ }
603
+
604
+ fn sig_for_projection < ' tcx > ( cx : & LateContext < ' tcx > , ty : ProjectionTy < ' tcx > ) -> Option < ExprFnSig < ' tcx > > {
605
+ let mut inputs = None ;
606
+ let mut output = None ;
607
+ let lang_items = cx. tcx . lang_items ( ) ;
595
608
596
- inputs. map ( |ty| ExprFnSig :: Trait ( ty, output) )
609
+ for pred in cx
610
+ . tcx
611
+ . bound_explicit_item_bounds ( ty. item_def_id )
612
+ . transpose_iter ( )
613
+ . map ( |x| x. map_bound ( |( p, _) | p) )
614
+ {
615
+ match pred. 0 . kind ( ) . skip_binder ( ) {
616
+ PredicateKind :: Trait ( p)
617
+ if ( lang_items. fn_trait ( ) == Some ( p. def_id ( ) )
618
+ || lang_items. fn_mut_trait ( ) == Some ( p. def_id ( ) )
619
+ || lang_items. fn_once_trait ( ) == Some ( p. def_id ( ) ) ) =>
620
+ {
621
+ if inputs. is_some ( ) {
622
+ // Multiple different fn trait impls. Is this even allowed?
623
+ return None ;
624
+ }
625
+ inputs = Some (
626
+ pred. map_bound ( |pred| pred. kind ( ) . rebind ( p. trait_ref . substs . type_at ( 1 ) ) )
627
+ . subst ( cx. tcx , ty. substs ) ,
628
+ ) ;
597
629
} ,
598
- _ => None ,
630
+ PredicateKind :: Projection ( p) if Some ( p. projection_ty . item_def_id ) == lang_items. fn_once_output ( ) => {
631
+ if output. is_some ( ) {
632
+ // Multiple different fn trait impls. Is this even allowed?
633
+ return None ;
634
+ }
635
+ output = Some (
636
+ pred. map_bound ( |pred| pred. kind ( ) . rebind ( p. term . ty ( ) . unwrap ( ) ) )
637
+ . subst ( cx. tcx , ty. substs ) ,
638
+ ) ;
639
+ } ,
640
+ _ => ( ) ,
599
641
}
600
642
}
643
+
644
+ inputs. map ( |ty| ExprFnSig :: Trait ( ty, output) )
601
645
}
602
646
603
647
#[ derive( Clone , Copy ) ]
0 commit comments