@@ -70,8 +70,10 @@ use rustc_infer::infer::TyCtxtInferExt;
70
70
use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
71
71
use rustc_middle:: hir:: exports:: Export ;
72
72
use rustc_middle:: hir:: map:: Map ;
73
- use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind } ;
74
- use rustc_middle:: ty:: { self , layout:: IntegerExt , DefIdTree , Ty , TyCtxt , TypeFoldable } ;
73
+ use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
74
+ use rustc_middle:: ty:: {
75
+ self , layout:: IntegerExt , Binder , DefIdTree , FnSig , PredicateKind , Ty , TyCtxt , TypeFoldable , TypeckResults ,
76
+ } ;
75
77
use rustc_semver:: RustcVersion ;
76
78
use rustc_session:: Session ;
77
79
use rustc_span:: hygiene:: { self , ExpnKind , MacroKind } ;
@@ -1763,6 +1765,96 @@ where
1763
1765
match_expr_list
1764
1766
}
1765
1767
1768
+ /// If expr is a path, resolves it. Otherwise returns `None`.
1769
+ pub fn expr_res ( typeck : & TypeckResults < ' _ > , expr : & Expr < ' _ > ) -> Option < Res > {
1770
+ if let ExprKind :: Path ( p) = & expr. kind {
1771
+ Some ( typeck. qpath_res ( p, expr. hir_id ) )
1772
+ } else {
1773
+ None
1774
+ }
1775
+ }
1776
+
1777
+ /// A signature for a function like type.
1778
+ pub enum ExprFnSig < ' tcx > {
1779
+ Sig ( Binder < FnSig < ' tcx > > ) ,
1780
+ Closure ( Binder < FnSig < ' tcx > > ) ,
1781
+ Trait ( Binder < Ty < ' tcx > > ) ,
1782
+ }
1783
+ impl ExprFnSig < ' tcx > {
1784
+ /// Gets the argument type at the given offset.
1785
+ pub fn input ( & self , i : usize ) -> Binder < Ty < ' tcx > > {
1786
+ match self {
1787
+ Self :: Sig ( sig) => sig. input ( i) ,
1788
+ Self :: Closure ( sig) => sig. input ( 0 ) . map_bound ( |ty| ty. tuple_element_ty ( i) . unwrap ( ) ) ,
1789
+ Self :: Trait ( sig) => sig. map_bound ( |ty| ty. tuple_element_ty ( i) . unwrap ( ) ) ,
1790
+ }
1791
+ }
1792
+ }
1793
+
1794
+ /// If expr is function like, get the signature for it.
1795
+ pub fn expr_sig ( tcx : TyCtxt < ' tcx > , typeck : & TypeckResults < ' tcx > , expr : & Expr < ' _ > ) -> Option < ExprFnSig < ' tcx > > {
1796
+ match expr_res ( typeck, expr) {
1797
+ Some ( Res :: Def ( DefKind :: Fn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: AssocFn , id) | Res :: SelfCtor ( id) ) => {
1798
+ Some ( ExprFnSig :: Sig ( tcx. fn_sig ( id) ) )
1799
+ } ,
1800
+ _ => {
1801
+ let ty = typeck. expr_ty_adjusted ( expr) . peel_refs ( ) ;
1802
+ match * ty. kind ( ) {
1803
+ ty:: Closure ( _, subs) => Some ( ExprFnSig :: Closure ( subs. as_closure ( ) . sig ( ) ) ) ,
1804
+ ty:: FnDef ( id, subs) => Some ( ExprFnSig :: Sig ( tcx. fn_sig ( id) . subst ( tcx, subs) ) ) ,
1805
+ ty:: FnPtr ( sig) => Some ( ExprFnSig :: Sig ( sig) ) ,
1806
+ ty:: Dynamic ( bounds, _) => {
1807
+ let lang_items = tcx. lang_items ( ) ;
1808
+ match bounds. principal ( ) {
1809
+ Some ( bound)
1810
+ if Some ( bound. def_id ( ) ) == lang_items. fn_trait ( )
1811
+ || Some ( bound. def_id ( ) ) == lang_items. fn_once_trait ( )
1812
+ || Some ( bound. def_id ( ) ) == lang_items. fn_mut_trait ( ) =>
1813
+ {
1814
+ Some ( ExprFnSig :: Trait ( bound. map_bound ( |b| b. substs . type_at ( 0 ) ) ) )
1815
+ } ,
1816
+ _ => None ,
1817
+ }
1818
+ } ,
1819
+ ty:: Param ( _) | ty:: Projection ( ..) => {
1820
+ let mut id = typeck. hir_owner . to_def_id ( ) ;
1821
+ loop {
1822
+ let predicates = tcx. predicates_of ( id) ;
1823
+ let lang_items = tcx. lang_items ( ) ;
1824
+ if let Some ( res) = predicates
1825
+ . predicates
1826
+ . iter ( )
1827
+ . find_map ( |& ( p, _) | {
1828
+ p. kind ( )
1829
+ . map_bound ( |kind| match kind {
1830
+ PredicateKind :: Trait ( p, _)
1831
+ if ( lang_items. fn_trait ( ) == Some ( p. def_id ( ) )
1832
+ || lang_items. fn_mut_trait ( ) == Some ( p. def_id ( ) )
1833
+ || lang_items. fn_once_trait ( ) == Some ( p. def_id ( ) ) )
1834
+ && p. self_ty ( ) == ty =>
1835
+ {
1836
+ Some ( p. trait_ref . substs . type_at ( 1 ) )
1837
+ } ,
1838
+ _ => None ,
1839
+ } )
1840
+ . transpose ( )
1841
+ } )
1842
+ . map ( ExprFnSig :: Trait )
1843
+ {
1844
+ break Some ( res) ;
1845
+ } else if let Some ( parent_id) = predicates. parent {
1846
+ id = parent_id;
1847
+ } else {
1848
+ break None ;
1849
+ }
1850
+ }
1851
+ } ,
1852
+ _ => None ,
1853
+ }
1854
+ } ,
1855
+ }
1856
+ }
1857
+
1766
1858
/// Peels off all references on the pattern. Returns the underlying pattern and the number of
1767
1859
/// references removed.
1768
1860
pub fn peel_hir_pat_refs ( pat : & ' a Pat < ' a > ) -> ( & ' a Pat < ' a > , usize ) {
0 commit comments