@@ -501,7 +501,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
501501/// A signature for a function like type.
502502#[ derive( Clone , Copy ) ]
503503pub enum ExprFnSig < ' tcx > {
504- Sig ( Binder < ' tcx , FnSig < ' tcx > > ) ,
504+ Sig ( Binder < ' tcx , FnSig < ' tcx > > , Option < DefId > ) ,
505505 Closure ( Option < & ' tcx FnDecl < ' tcx > > , Binder < ' tcx , FnSig < ' tcx > > ) ,
506506 Trait ( Binder < ' tcx , Ty < ' tcx > > , Option < Binder < ' tcx , Ty < ' tcx > > > ) ,
507507}
@@ -510,7 +510,7 @@ impl<'tcx> ExprFnSig<'tcx> {
510510 /// bounds only for variadic functions, otherwise this will panic.
511511 pub fn input ( self , i : usize ) -> Option < Binder < ' tcx , Ty < ' tcx > > > {
512512 match self {
513- Self :: Sig ( sig) => {
513+ Self :: Sig ( sig, _ ) => {
514514 if sig. c_variadic ( ) {
515515 sig. inputs ( ) . map_bound ( |inputs| inputs. get ( i) . copied ( ) ) . transpose ( )
516516 } else {
@@ -527,7 +527,7 @@ impl<'tcx> ExprFnSig<'tcx> {
527527 /// functions, otherwise this will panic.
528528 pub fn input_with_hir ( self , i : usize ) -> Option < ( Option < & ' tcx hir:: Ty < ' tcx > > , Binder < ' tcx , Ty < ' tcx > > ) > {
529529 match self {
530- Self :: Sig ( sig) => {
530+ Self :: Sig ( sig, _ ) => {
531531 if sig. c_variadic ( ) {
532532 sig. inputs ( )
533533 . map_bound ( |inputs| inputs. get ( i) . copied ( ) )
@@ -549,16 +549,20 @@ impl<'tcx> ExprFnSig<'tcx> {
549549 /// specified.
550550 pub fn output ( self ) -> Option < Binder < ' tcx , Ty < ' tcx > > > {
551551 match self {
552- Self :: Sig ( sig) | Self :: Closure ( _, sig) => Some ( sig. output ( ) ) ,
552+ Self :: Sig ( sig, _ ) | Self :: Closure ( _, sig) => Some ( sig. output ( ) ) ,
553553 Self :: Trait ( _, output) => output,
554554 }
555555 }
556+
557+ pub fn predicates_id ( & self ) -> Option < DefId > {
558+ if let ExprFnSig :: Sig ( _, id) = * self { id } else { None }
559+ }
556560}
557561
558562/// If the expression is function like, get the signature for it.
559563pub fn expr_sig < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' _ > ) -> Option < ExprFnSig < ' tcx > > {
560564 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 ) ) )
562566 } else {
563567 ty_sig ( cx, cx. typeck_results ( ) . expr_ty_adjusted ( expr) . peel_refs ( ) )
564568 }
@@ -575,9 +579,9 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
575579 . and_then ( |id| cx. tcx . hir ( ) . fn_decl_by_hir_id ( cx. tcx . hir ( ) . local_def_id_to_hir_id ( id) ) ) ;
576580 Some ( ExprFnSig :: Closure ( decl, subs. as_closure ( ) . sig ( ) ) )
577581 } ,
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 ) ) ) ,
579583 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 ) ) ,
581585 ty:: Dynamic ( bounds, _) => {
582586 let lang_items = cx. tcx . lang_items ( ) ;
583587 match bounds. principal ( ) {
@@ -793,3 +797,33 @@ pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx Va
793797 _ => None ,
794798 }
795799}
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