@@ -501,7 +501,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
501
501
/// A signature for a function like type.
502
502
#[ derive( Clone , Copy ) ]
503
503
pub enum ExprFnSig < ' tcx > {
504
- Sig ( Binder < ' tcx , FnSig < ' tcx > > ) ,
504
+ Sig ( Binder < ' tcx , FnSig < ' tcx > > , Option < DefId > ) ,
505
505
Closure ( Option < & ' tcx FnDecl < ' tcx > > , Binder < ' tcx , FnSig < ' tcx > > ) ,
506
506
Trait ( Binder < ' tcx , Ty < ' tcx > > , Option < Binder < ' tcx , Ty < ' tcx > > > ) ,
507
507
}
@@ -510,7 +510,7 @@ impl<'tcx> ExprFnSig<'tcx> {
510
510
/// bounds only for variadic functions, otherwise this will panic.
511
511
pub fn input ( self , i : usize ) -> Option < Binder < ' tcx , Ty < ' tcx > > > {
512
512
match self {
513
- Self :: Sig ( sig) => {
513
+ Self :: Sig ( sig, _ ) => {
514
514
if sig. c_variadic ( ) {
515
515
sig. inputs ( ) . map_bound ( |inputs| inputs. get ( i) . copied ( ) ) . transpose ( )
516
516
} else {
@@ -527,7 +527,7 @@ impl<'tcx> ExprFnSig<'tcx> {
527
527
/// functions, otherwise this will panic.
528
528
pub fn input_with_hir ( self , i : usize ) -> Option < ( Option < & ' tcx hir:: Ty < ' tcx > > , Binder < ' tcx , Ty < ' tcx > > ) > {
529
529
match self {
530
- Self :: Sig ( sig) => {
530
+ Self :: Sig ( sig, _ ) => {
531
531
if sig. c_variadic ( ) {
532
532
sig. inputs ( )
533
533
. map_bound ( |inputs| inputs. get ( i) . copied ( ) )
@@ -549,16 +549,20 @@ impl<'tcx> ExprFnSig<'tcx> {
549
549
/// specified.
550
550
pub fn output ( self ) -> Option < Binder < ' tcx , Ty < ' tcx > > > {
551
551
match self {
552
- Self :: Sig ( sig) | Self :: Closure ( _, sig) => Some ( sig. output ( ) ) ,
552
+ Self :: Sig ( sig, _ ) | Self :: Closure ( _, sig) => Some ( sig. output ( ) ) ,
553
553
Self :: Trait ( _, output) => output,
554
554
}
555
555
}
556
+
557
+ pub fn predicates_id ( & self ) -> Option < DefId > {
558
+ if let ExprFnSig :: Sig ( _, id) = * self { id } else { None }
559
+ }
556
560
}
557
561
558
562
/// If the expression is function like, get the signature for it.
559
563
pub fn expr_sig < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' _ > ) -> Option < ExprFnSig < ' tcx > > {
560
564
if let Res :: Def ( DefKind :: Fn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: AssocFn , id) = path_res ( cx, expr) {
561
- Some ( ExprFnSig :: Sig ( cx. tcx . fn_sig ( id) ) )
565
+ Some ( ExprFnSig :: Sig ( cx. tcx . fn_sig ( id) , Some ( id ) ) )
562
566
} else {
563
567
ty_sig ( cx, cx. typeck_results ( ) . expr_ty_adjusted ( expr) . peel_refs ( ) )
564
568
}
@@ -575,9 +579,9 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
575
579
. and_then ( |id| cx. tcx . hir ( ) . fn_decl_by_hir_id ( cx. tcx . hir ( ) . local_def_id_to_hir_id ( id) ) ) ;
576
580
Some ( ExprFnSig :: Closure ( decl, subs. as_closure ( ) . sig ( ) ) )
577
581
} ,
578
- ty:: FnDef ( id, subs) => Some ( ExprFnSig :: Sig ( cx. tcx . bound_fn_sig ( id) . subst ( cx. tcx , subs) ) ) ,
582
+ ty:: FnDef ( id, subs) => Some ( ExprFnSig :: Sig ( cx. tcx . bound_fn_sig ( id) . subst ( cx. tcx , subs) , Some ( id ) ) ) ,
579
583
ty:: Opaque ( id, _) => ty_sig ( cx, cx. tcx . type_of ( id) ) ,
580
- ty:: FnPtr ( sig) => Some ( ExprFnSig :: Sig ( sig) ) ,
584
+ ty:: FnPtr ( sig) => Some ( ExprFnSig :: Sig ( sig, None ) ) ,
581
585
ty:: Dynamic ( bounds, _) => {
582
586
let lang_items = cx. tcx . lang_items ( ) ;
583
587
match bounds. principal ( ) {
@@ -793,3 +797,33 @@ pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx Va
793
797
_ => None ,
794
798
}
795
799
}
800
+
801
+ /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
802
+ pub fn ty_is_fn_once_param < ' tcx > ( tcx : TyCtxt < ' _ > , ty : Ty < ' tcx > , predicates : & ' tcx [ Predicate < ' _ > ] ) -> bool {
803
+ let ty:: Param ( ty) = * ty. kind ( ) else {
804
+ return false ;
805
+ } ;
806
+ let lang = tcx. lang_items ( ) ;
807
+ let ( Some ( fn_once_id) , Some ( fn_mut_id) , Some ( fn_id) )
808
+ = ( lang. fn_once_trait ( ) , lang. fn_mut_trait ( ) , lang. fn_trait ( ) )
809
+ else {
810
+ return false ;
811
+ } ;
812
+ predicates
813
+ . iter ( )
814
+ . try_fold ( false , |found, p| {
815
+ if let PredicateKind :: Trait ( p) = p. kind ( ) . skip_binder ( )
816
+ && let ty:: Param ( self_ty) = p. trait_ref . self_ty ( ) . kind ( )
817
+ && ty. index == self_ty. index
818
+ {
819
+ // This should use `super_traits_of`, but that's a private function.
820
+ if p. trait_ref . def_id == fn_once_id {
821
+ return Some ( true ) ;
822
+ } else if p. trait_ref . def_id == fn_mut_id || p. trait_ref . def_id == fn_id {
823
+ return None ;
824
+ }
825
+ }
826
+ Some ( found)
827
+ } )
828
+ . unwrap_or ( false )
829
+ }
0 commit comments