@@ -1682,49 +1682,70 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1682
1682
bound_kind : GenericKind < ' tcx > ,
1683
1683
sub : Region < ' tcx > ,
1684
1684
) -> DiagnosticBuilder < ' a > {
1685
+ let hir = & self . tcx . hir ( ) ;
1685
1686
// Attempt to obtain the span of the parameter so we can
1686
1687
// suggest adding an explicit lifetime bound to it.
1687
- let type_param_span = match ( self . in_progress_tables , bound_kind) {
1688
- ( Some ( ref table) , GenericKind :: Param ( ref param) ) => {
1689
- let table_owner = table. borrow ( ) . hir_owner ;
1690
- table_owner. and_then ( |table_owner| {
1691
- let generics = self . tcx . generics_of ( table_owner. to_def_id ( ) ) ;
1692
- // Account for the case where `param` corresponds to `Self`,
1693
- // which doesn't have the expected type argument.
1694
- if !( generics. has_self && param. index == 0 ) {
1695
- let type_param = generics. type_param ( param, self . tcx ) ;
1696
- let hir = & self . tcx . hir ( ) ;
1697
- type_param. def_id . as_local ( ) . map ( |def_id| {
1698
- // Get the `hir::Param` to verify whether it already has any bounds.
1699
- // We do this to avoid suggesting code that ends up as `T: 'a'b`,
1700
- // instead we suggest `T: 'a + 'b` in that case.
1701
- let id = hir. as_local_hir_id ( def_id) ;
1702
- let mut has_bounds = false ;
1703
- if let Node :: GenericParam ( param) = hir. get ( id) {
1704
- has_bounds = !param. bounds . is_empty ( ) ;
1705
- }
1706
- let sp = hir. span ( id) ;
1707
- // `sp` only covers `T`, change it so that it covers
1708
- // `T:` when appropriate
1709
- let is_impl_trait = bound_kind. to_string ( ) . starts_with ( "impl " ) ;
1710
- let sp = if has_bounds && !is_impl_trait {
1711
- sp. to ( self
1712
- . tcx
1713
- . sess
1714
- . source_map ( )
1715
- . next_point ( self . tcx . sess . source_map ( ) . next_point ( sp) ) )
1716
- } else {
1717
- sp
1718
- } ;
1719
- ( sp, has_bounds, is_impl_trait)
1720
- } )
1721
- } else {
1722
- None
1723
- }
1724
- } )
1688
+ let generics = self
1689
+ . in_progress_tables
1690
+ . and_then ( |table| table. borrow ( ) . hir_owner )
1691
+ . map ( |table_owner| self . tcx . generics_of ( table_owner. to_def_id ( ) ) ) ;
1692
+ let type_param_span = match ( generics, bound_kind) {
1693
+ ( Some ( ref generics) , GenericKind :: Param ( ref param) ) => {
1694
+ // Account for the case where `param` corresponds to `Self`,
1695
+ // which doesn't have the expected type argument.
1696
+ if !( generics. has_self && param. index == 0 ) {
1697
+ let type_param = generics. type_param ( param, self . tcx ) ;
1698
+ type_param. def_id . as_local ( ) . map ( |def_id| {
1699
+ // Get the `hir::Param` to verify whether it already has any bounds.
1700
+ // We do this to avoid suggesting code that ends up as `T: 'a'b`,
1701
+ // instead we suggest `T: 'a + 'b` in that case.
1702
+ let id = hir. as_local_hir_id ( def_id) ;
1703
+ let mut has_bounds = false ;
1704
+ if let Node :: GenericParam ( param) = hir. get ( id) {
1705
+ has_bounds = !param. bounds . is_empty ( ) ;
1706
+ }
1707
+ let sp = hir. span ( id) ;
1708
+ // `sp` only covers `T`, change it so that it covers
1709
+ // `T:` when appropriate
1710
+ let is_impl_trait = bound_kind. to_string ( ) . starts_with ( "impl " ) ;
1711
+ let sp = if has_bounds && !is_impl_trait {
1712
+ sp. to ( self
1713
+ . tcx
1714
+ . sess
1715
+ . source_map ( )
1716
+ . next_point ( self . tcx . sess . source_map ( ) . next_point ( sp) ) )
1717
+ } else {
1718
+ sp
1719
+ } ;
1720
+ ( sp, has_bounds, is_impl_trait)
1721
+ } )
1722
+ } else {
1723
+ None
1724
+ }
1725
1725
}
1726
1726
_ => None ,
1727
1727
} ;
1728
+ let new_lt = generics
1729
+ . as_ref ( )
1730
+ . and_then ( |g| {
1731
+ let possible = [ "'a" , "'b" , "'c" , "'d" , "'e" , "'f" , "'g" , "'h" , "'i" , "'j" , "'k" ] ;
1732
+ let lts_names = g
1733
+ . params
1734
+ . iter ( )
1735
+ . filter ( |p| matches ! ( p. kind, ty:: GenericParamDefKind :: Lifetime ) )
1736
+ . map ( |p| p. name . as_str ( ) )
1737
+ . collect :: < Vec < _ > > ( ) ;
1738
+ let lts = lts_names. iter ( ) . map ( |s| -> & str { & * s } ) . collect :: < Vec < _ > > ( ) ;
1739
+ possible. iter ( ) . filter ( |& candidate| !lts. contains ( & * candidate) ) . next ( ) . map ( |s| * s)
1740
+ } )
1741
+ . unwrap_or ( "'lt" ) ;
1742
+ let add_lt_sugg = generics
1743
+ . as_ref ( )
1744
+ . and_then ( |g| g. params . first ( ) )
1745
+ . and_then ( |param| param. def_id . as_local ( ) )
1746
+ . map ( |def_id| {
1747
+ ( hir. span ( hir. as_local_hir_id ( def_id) ) . shrink_to_lo ( ) , format ! ( "{}, " , new_lt) )
1748
+ } ) ;
1728
1749
1729
1750
let labeled_user_string = match bound_kind {
1730
1751
GenericKind :: Param ( ref p) => format ! ( "the parameter type `{}`" , p) ,
@@ -1781,6 +1802,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1781
1802
}
1782
1803
}
1783
1804
1805
+ let new_binding_suggestion =
1806
+ |err : & mut DiagnosticBuilder < ' tcx > ,
1807
+ type_param_span : Option < ( Span , bool , bool ) > ,
1808
+ bound_kind : GenericKind < ' tcx > | {
1809
+ let msg = "consider introducing an explicit lifetime bound to unify the type \
1810
+ parameter and the output";
1811
+ if let Some ( ( sp, has_lifetimes, is_impl_trait) ) = type_param_span {
1812
+ let suggestion = if is_impl_trait {
1813
+ ( sp. shrink_to_hi ( ) , format ! ( " + {}" , new_lt) )
1814
+ } else {
1815
+ let tail = if has_lifetimes { " +" } else { "" } ;
1816
+ ( sp, format ! ( "{}: {}{}" , bound_kind, new_lt, tail) )
1817
+ } ;
1818
+ let mut sugg =
1819
+ vec ! [ suggestion, ( span. shrink_to_hi( ) , format!( " + {}" , new_lt) ) ] ;
1820
+ if let Some ( lt) = add_lt_sugg {
1821
+ sugg. push ( lt) ;
1822
+ sugg. rotate_right ( 1 ) ;
1823
+ }
1824
+ // `MaybeIncorrect` due to issue #41966.
1825
+ err. multipart_suggestion ( msg, sugg, Applicability :: MaybeIncorrect ) ;
1826
+ }
1827
+ } ;
1828
+
1784
1829
let mut err = match * sub {
1785
1830
ty:: ReEarlyBound ( ty:: EarlyBoundRegion { name, .. } )
1786
1831
| ty:: ReFree ( ty:: FreeRegion { bound_region : ty:: BrNamed ( _, name) , .. } ) => {
@@ -1822,17 +1867,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1822
1867
"{} may not live long enough" ,
1823
1868
labeled_user_string
1824
1869
) ;
1825
- err. help ( & format ! (
1826
- "consider adding an explicit lifetime bound for `{}`" ,
1827
- bound_kind
1828
- ) ) ;
1829
1870
note_and_explain_region (
1830
1871
self . tcx ,
1831
1872
& mut err,
1832
1873
& format ! ( "{} must be valid for " , labeled_user_string) ,
1833
1874
sub,
1834
1875
"..." ,
1835
1876
) ;
1877
+ if let Some ( infer:: RelateParamBound ( _, t) ) = origin {
1878
+ let t = self . resolve_vars_if_possible ( & t) ;
1879
+ match t. kind {
1880
+ // We've got:
1881
+ // fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
1882
+ // suggest:
1883
+ // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
1884
+ ty:: Closure ( _, _substs) | ty:: Opaque ( _, _substs) => {
1885
+ new_binding_suggestion ( & mut err, type_param_span, bound_kind) ;
1886
+ }
1887
+ _ => {
1888
+ binding_suggestion ( & mut err, type_param_span, bound_kind, new_lt) ;
1889
+ }
1890
+ }
1891
+ }
1836
1892
err
1837
1893
}
1838
1894
} ;
0 commit comments