@@ -14,8 +14,8 @@ use rustc_lint::LateContext;
1414use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
1515use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
1616use 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 ,
1919} ;
2020use rustc_span:: symbol:: Ident ;
2121use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
@@ -530,74 +530,118 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
530530 if let Res :: Def ( DefKind :: Fn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: AssocFn , id) = path_res ( cx, expr) {
531531 Some ( ExprFnSig :: Sig ( cx. tcx . fn_sig ( id) ) )
532532 } 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 ;
553584 }
585+ inputs = Some ( pred. kind ( ) . rebind ( p. trait_ref . substs . type_at ( 1 ) ) ) ;
554586 } ,
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 ;
594594 }
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 ( ) ;
595608
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+ ) ;
597629 } ,
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+ _ => ( ) ,
599641 }
600642 }
643+
644+ inputs. map ( |ty| ExprFnSig :: Trait ( ty, output) )
601645}
602646
603647#[ derive( Clone , Copy ) ]
0 commit comments