2323
2424use rustc:: hir:: def:: { Res , DefKind } ;
2525use rustc:: hir:: def_id:: { DefId , LOCAL_CRATE } ;
26- use rustc:: ty:: { self , Ty } ;
26+ use rustc:: ty:: { self , Ty , TyCtxt } ;
2727use rustc:: { lint, util} ;
2828use hir:: Node ;
2929use util:: nodemap:: HirIdSet ;
@@ -1494,58 +1494,107 @@ impl EarlyLintPass for KeywordIdents {
14941494declare_lint_pass ! ( ExplicitOutlivesRequirements => [ EXPLICIT_OUTLIVES_REQUIREMENTS ] ) ;
14951495
14961496impl ExplicitOutlivesRequirements {
1497- fn collect_outlives_bound_spans (
1498- & self ,
1499- cx : & LateContext < ' _ , ' _ > ,
1500- item_def_id : DefId ,
1501- param_name : & str ,
1502- bounds : & hir:: GenericBounds ,
1503- infer_static : bool
1504- ) -> Vec < ( usize , Span ) > {
1505- // For lack of a more elegant strategy for comparing the `ty::Predicate`s
1506- // returned by this query with the params/bounds grabbed from the HIR—and
1507- // with some regrets—we're going to covert the param/lifetime names to
1508- // strings
1509- let inferred_outlives = cx. tcx . inferred_outlives_of ( item_def_id) ;
1510-
1511- let ty_lt_names = inferred_outlives. iter ( ) . filter_map ( |pred| {
1512- let binder = match pred {
1513- ty:: Predicate :: TypeOutlives ( binder) => binder,
1514- _ => { return None ; }
1515- } ;
1516- let ty_outlives_pred = binder. skip_binder ( ) ;
1517- let ty_name = match ty_outlives_pred. 0 . sty {
1518- ty:: Param ( param) => param. name . to_string ( ) ,
1519- _ => { return None ; }
1520- } ;
1521- let lt_name = match ty_outlives_pred. 1 {
1522- ty:: RegionKind :: ReEarlyBound ( region) => {
1523- region. name . to_string ( )
1524- } ,
1525- _ => { return None ; }
1526- } ;
1527- Some ( ( ty_name, lt_name) )
1528- } ) . collect :: < Vec < _ > > ( ) ;
1529-
1530- let mut bound_spans = Vec :: new ( ) ;
1531- for ( i, bound) in bounds. iter ( ) . enumerate ( ) {
1532- if let hir:: GenericBound :: Outlives ( lifetime) = bound {
1533- let is_static = match lifetime. name {
1534- hir:: LifetimeName :: Static => true ,
1535- _ => false
1536- } ;
1537- if is_static && !infer_static {
1538- // infer-outlives for 'static is still feature-gated (tracking issue #44493)
1539- continue ;
1497+ fn lifetimes_outliving_lifetime < ' tcx > (
1498+ inferred_outlives : & ' tcx [ ty:: Predicate < ' tcx > ] ,
1499+ index : u32 ,
1500+ ) -> Vec < ty:: Region < ' tcx > > {
1501+ inferred_outlives. iter ( ) . filter_map ( |pred| {
1502+ match pred {
1503+ ty:: Predicate :: RegionOutlives ( outlives) => {
1504+ let outlives = outlives. skip_binder ( ) ;
1505+ match outlives. 0 {
1506+ ty:: ReEarlyBound ( ebr) if ebr. index == index => {
1507+ Some ( outlives. 1 )
1508+ }
1509+ _ => None ,
1510+ }
15401511 }
1512+ _ => None
1513+ }
1514+ } ) . collect ( )
1515+ }
15411516
1542- let lt_name = & lifetime. name . ident ( ) . to_string ( ) ;
1543- if ty_lt_names. contains ( & ( param_name. to_owned ( ) , lt_name. to_owned ( ) ) ) {
1544- bound_spans. push ( ( i, bound. span ( ) ) ) ;
1517+ fn lifetimes_outliving_type < ' tcx > (
1518+ inferred_outlives : & ' tcx [ ty:: Predicate < ' tcx > ] ,
1519+ index : u32 ,
1520+ ) -> Vec < ty:: Region < ' tcx > > {
1521+ inferred_outlives. iter ( ) . filter_map ( |pred| {
1522+ match pred {
1523+ ty:: Predicate :: TypeOutlives ( outlives) => {
1524+ let outlives = outlives. skip_binder ( ) ;
1525+ if outlives. 0 . is_param ( index) {
1526+ Some ( outlives. 1 )
1527+ } else {
1528+ None
1529+ }
15451530 }
1531+ _ => None
1532+ }
1533+ } ) . collect ( )
1534+ }
1535+
1536+ fn collect_outlived_lifetimes < ' tcx > (
1537+ & self ,
1538+ param : & ' tcx hir:: GenericParam ,
1539+ tcx : TyCtxt < ' tcx > ,
1540+ inferred_outlives : & ' tcx [ ty:: Predicate < ' tcx > ] ,
1541+ ty_generics : & ' tcx ty:: Generics ,
1542+ ) -> Vec < ty:: Region < ' tcx > > {
1543+ let index = ty_generics. param_def_id_to_index [
1544+ & tcx. hir ( ) . local_def_id_from_hir_id ( param. hir_id ) ] ;
1545+
1546+ match param. kind {
1547+ hir:: GenericParamKind :: Lifetime { .. } => {
1548+ Self :: lifetimes_outliving_lifetime ( inferred_outlives, index)
1549+ }
1550+ hir:: GenericParamKind :: Type { .. } => {
1551+ Self :: lifetimes_outliving_type ( inferred_outlives, index)
15461552 }
1553+ hir:: GenericParamKind :: Const { .. } => Vec :: new ( ) ,
15471554 }
1548- bound_spans
1555+ }
1556+
1557+
1558+ fn collect_outlives_bound_spans < ' tcx > (
1559+ & self ,
1560+ tcx : TyCtxt < ' tcx > ,
1561+ bounds : & hir:: GenericBounds ,
1562+ inferred_outlives : & [ ty:: Region < ' tcx > ] ,
1563+ infer_static : bool ,
1564+ ) -> Vec < ( usize , Span ) > {
1565+ use rustc:: middle:: resolve_lifetime:: Region ;
1566+
1567+ bounds
1568+ . iter ( )
1569+ . enumerate ( )
1570+ . filter_map ( |( i, bound) | {
1571+ if let hir:: GenericBound :: Outlives ( lifetime) = bound {
1572+ let is_inferred = match tcx. named_region ( lifetime. hir_id ) {
1573+ Some ( Region :: Static ) if infer_static => {
1574+ inferred_outlives. iter ( )
1575+ . any ( |r| if let ty:: ReStatic = r { true } else { false } )
1576+ }
1577+ Some ( Region :: EarlyBound ( index, ..) ) => inferred_outlives
1578+ . iter ( )
1579+ . any ( |r| {
1580+ if let ty:: ReEarlyBound ( ebr) = r {
1581+ ebr. index == index
1582+ } else {
1583+ false
1584+ }
1585+ } ) ,
1586+ _ => false ,
1587+ } ;
1588+ if is_inferred {
1589+ Some ( ( i, bound. span ( ) ) )
1590+ } else {
1591+ None
1592+ }
1593+ } else {
1594+ None
1595+ }
1596+ } )
1597+ . collect ( )
15491598 }
15501599
15511600 fn consolidate_outlives_bound_spans (
@@ -1569,7 +1618,7 @@ impl ExplicitOutlivesRequirements {
15691618 let mut from_start = true ;
15701619 for ( i, bound_span) in bound_spans {
15711620 match last_merged_i {
1572- // If the first bound is inferable, our span should also eat the trailing `+`
1621+ // If the first bound is inferable, our span should also eat the leading `+`
15731622 None if i == 0 => {
15741623 merged. push ( bound_span. to ( bounds[ 1 ] . span ( ) . shrink_to_lo ( ) ) ) ;
15751624 last_merged_i = Some ( 0 ) ;
@@ -1607,26 +1656,48 @@ impl ExplicitOutlivesRequirements {
16071656
16081657impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ExplicitOutlivesRequirements {
16091658 fn check_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx hir:: Item ) {
1659+ use rustc:: middle:: resolve_lifetime:: Region ;
1660+
16101661 let infer_static = cx. tcx . features ( ) . infer_static_outlives_requirements ;
16111662 let def_id = cx. tcx . hir ( ) . local_def_id_from_hir_id ( item. hir_id ) ;
1612- if let hir:: ItemKind :: Struct ( _, ref generics) = item. node {
1663+ if let hir:: ItemKind :: Struct ( _, ref hir_generics)
1664+ | hir:: ItemKind :: Enum ( _, ref hir_generics)
1665+ | hir:: ItemKind :: Union ( _, ref hir_generics) = item. node
1666+ {
1667+ let inferred_outlives = cx. tcx . inferred_outlives_of ( def_id) ;
1668+ if inferred_outlives. is_empty ( ) {
1669+ return ;
1670+ }
1671+
1672+ let ty_generics = cx. tcx . generics_of ( def_id) ;
1673+
16131674 let mut bound_count = 0 ;
16141675 let mut lint_spans = Vec :: new ( ) ;
16151676
1616- for param in & generics. params {
1617- let param_name = match param. kind {
1618- hir:: GenericParamKind :: Lifetime { .. } => continue ,
1619- hir:: GenericParamKind :: Type { .. } => {
1620- match param. name {
1621- hir:: ParamName :: Fresh ( _) => continue ,
1622- hir:: ParamName :: Error => continue ,
1623- hir:: ParamName :: Plain ( name) => name. to_string ( ) ,
1624- }
1677+ for param in & hir_generics. params {
1678+ let has_lifetime_bounds = param. bounds . iter ( ) . any ( |bound| {
1679+ if let hir:: GenericBound :: Outlives ( _) = bound {
1680+ true
1681+ } else {
1682+ false
16251683 }
1626- hir:: GenericParamKind :: Const { .. } => continue ,
1627- } ;
1684+ } ) ;
1685+ if !has_lifetime_bounds {
1686+ continue ;
1687+ }
1688+
1689+ let relevant_lifetimes = self . collect_outlived_lifetimes (
1690+ param,
1691+ cx. tcx ,
1692+ inferred_outlives,
1693+ ty_generics,
1694+ ) ;
1695+ if relevant_lifetimes. is_empty ( ) {
1696+ continue ;
1697+ }
1698+
16281699 let bound_spans = self . collect_outlives_bound_spans (
1629- cx, def_id , & param_name , & param. bounds , infer_static
1700+ cx. tcx , & param. bounds , & relevant_lifetimes , infer_static,
16301701 ) ;
16311702 bound_count += bound_spans. len ( ) ;
16321703 lint_spans. extend (
@@ -1638,54 +1709,92 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
16381709
16391710 let mut where_lint_spans = Vec :: new ( ) ;
16401711 let mut dropped_predicate_count = 0 ;
1641- let num_predicates = generics. where_clause . predicates . len ( ) ;
1642- for ( i, where_predicate) in generics. where_clause . predicates . iter ( ) . enumerate ( ) {
1643- if let hir:: WherePredicate :: BoundPredicate ( predicate) = where_predicate {
1644- let param_name = match predicate. bounded_ty . node {
1645- hir:: TyKind :: Path ( ref qpath) => {
1646- if let hir:: QPath :: Resolved ( None , ty_param_path) = qpath {
1647- ty_param_path. segments [ 0 ] . ident . to_string ( )
1648- } else {
1649- continue ;
1650- }
1651- } ,
1652- _ => { continue ; }
1653- } ;
1654- let bound_spans = self . collect_outlives_bound_spans (
1655- cx, def_id, & param_name, & predicate. bounds , infer_static
1656- ) ;
1657- bound_count += bound_spans. len ( ) ;
1658-
1659- let drop_predicate = bound_spans. len ( ) == predicate. bounds . len ( ) ;
1660- if drop_predicate {
1661- dropped_predicate_count += 1 ;
1662- }
1663-
1664- // If all the bounds on a predicate were inferable and there are
1665- // further predicates, we want to eat the trailing comma
1666- if drop_predicate && i + 1 < num_predicates {
1667- let next_predicate_span = generics. where_clause . predicates [ i+1 ] . span ( ) ;
1668- where_lint_spans. push (
1669- predicate. span . to ( next_predicate_span. shrink_to_lo ( ) )
1670- ) ;
1671- } else {
1672- where_lint_spans. extend (
1673- self . consolidate_outlives_bound_spans (
1674- predicate. span . shrink_to_lo ( ) ,
1712+ let num_predicates = hir_generics. where_clause . predicates . len ( ) ;
1713+ for ( i, where_predicate) in hir_generics. where_clause . predicates . iter ( ) . enumerate ( ) {
1714+ let ( relevant_lifetimes, bounds, span) = match where_predicate {
1715+ hir:: WherePredicate :: RegionPredicate ( predicate) => {
1716+ if let Some ( Region :: EarlyBound ( index, ..) )
1717+ = cx. tcx . named_region ( predicate. lifetime . hir_id )
1718+ {
1719+ (
1720+ Self :: lifetimes_outliving_lifetime ( inferred_outlives, index) ,
16751721 & predicate. bounds ,
1676- bound_spans
1722+ predicate . span ,
16771723 )
1678- ) ;
1724+ } else {
1725+ continue ;
1726+ }
16791727 }
1728+ hir:: WherePredicate :: BoundPredicate ( predicate) => {
1729+ // FIXME we can also infer bounds on associated types,
1730+ // and should check for them here.
1731+ match predicate. bounded_ty . node {
1732+ hir:: TyKind :: Path ( hir:: QPath :: Resolved (
1733+ None ,
1734+ ref path,
1735+ ) ) => if let Res :: Def ( DefKind :: TyParam , def_id) = path. res {
1736+ let index = ty_generics. param_def_id_to_index [ & def_id] ;
1737+ (
1738+ Self :: lifetimes_outliving_type ( inferred_outlives, index) ,
1739+ & predicate. bounds ,
1740+ predicate. span ,
1741+ )
1742+ } else {
1743+ continue
1744+ } ,
1745+ _ => { continue ; }
1746+ }
1747+ }
1748+ _ => continue ,
1749+ } ;
1750+ if relevant_lifetimes. is_empty ( ) {
1751+ continue ;
1752+ }
1753+
1754+ let bound_spans = self . collect_outlives_bound_spans (
1755+ cx. tcx , bounds, & relevant_lifetimes, infer_static,
1756+ ) ;
1757+ bound_count += bound_spans. len ( ) ;
1758+
1759+ let drop_predicate = bound_spans. len ( ) == bounds. len ( ) ;
1760+ if drop_predicate {
1761+ dropped_predicate_count += 1 ;
1762+ }
1763+
1764+ // If all the bounds on a predicate were inferable and there are
1765+ // further predicates, we want to eat the trailing comma
1766+ if drop_predicate && i + 1 < num_predicates {
1767+ let next_predicate_span = hir_generics. where_clause . predicates [ i+1 ] . span ( ) ;
1768+ where_lint_spans. push (
1769+ span. to ( next_predicate_span. shrink_to_lo ( ) )
1770+ ) ;
1771+ } else {
1772+ where_lint_spans. extend (
1773+ self . consolidate_outlives_bound_spans (
1774+ span. shrink_to_lo ( ) ,
1775+ bounds,
1776+ bound_spans
1777+ )
1778+ ) ;
16801779 }
16811780 }
16821781
16831782 // If all predicates are inferable, drop the entire clause
16841783 // (including the `where`)
16851784 if num_predicates > 0 && dropped_predicate_count == num_predicates {
1686- let full_where_span = generics. span . shrink_to_hi ( )
1687- . to ( generics. where_clause . span ( )
1688- . expect ( "span of (nonempty) where clause should exist" ) ) ;
1785+ let where_span = hir_generics. where_clause . span ( )
1786+ . expect ( "span of (nonempty) where clause should exist" ) ;
1787+ // Extend the where clause back to the closing `>` of the
1788+ // generics, except for tuple struct, which have the `where`
1789+ // after the fields of the struct.
1790+ let full_where_span = match item. node {
1791+ hir:: ItemKind :: Struct ( hir:: VariantData :: Tuple ( ..) , _) => {
1792+ where_span
1793+ }
1794+ _ => {
1795+ hir_generics. span . shrink_to_hi ( ) . to ( where_span)
1796+ }
1797+ } ;
16891798 lint_spans. push (
16901799 full_where_span
16911800 ) ;
0 commit comments