@@ -60,7 +60,7 @@ use rustc_errors::{pluralize, struct_span_err};
60
60
use rustc_errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString } ;
61
61
use rustc_hir as hir;
62
62
use rustc_hir:: def_id:: DefId ;
63
- use rustc_hir:: Node ;
63
+ use rustc_hir:: { Item , ItemKind , Node } ;
64
64
use rustc_middle:: ty:: error:: TypeError ;
65
65
use rustc_middle:: ty:: {
66
66
self ,
@@ -1682,49 +1682,92 @@ 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
- } )
1688
+ let generics =
1689
+ self . in_progress_tables . and_then ( |table| table. borrow ( ) . hir_owner ) . map ( |table_owner| {
1690
+ let hir_id = hir. as_local_hir_id ( table_owner) ;
1691
+ let parent_id = hir. get_parent_item ( hir_id) ;
1692
+ (
1693
+ // Parent item could be a `mod`, so we check the HIR before calling:
1694
+ if let Some ( Node :: Item ( Item {
1695
+ kind : ItemKind :: Trait ( ..) | ItemKind :: Impl { .. } ,
1696
+ ..
1697
+ } ) ) = hir. find ( parent_id)
1698
+ {
1699
+ Some ( self . tcx . generics_of ( hir. local_def_id ( parent_id) . to_def_id ( ) ) )
1721
1700
} else {
1722
1701
None
1723
- }
1724
- } )
1702
+ } ,
1703
+ self . tcx . generics_of ( table_owner. to_def_id ( ) ) ,
1704
+ )
1705
+ } ) ;
1706
+ let type_param_span = match ( generics, bound_kind) {
1707
+ ( Some ( ( _, ref generics) ) , GenericKind :: Param ( ref param) ) => {
1708
+ // Account for the case where `param` corresponds to `Self`,
1709
+ // which doesn't have the expected type argument.
1710
+ if !( generics. has_self && param. index == 0 ) {
1711
+ let type_param = generics. type_param ( param, self . tcx ) ;
1712
+ type_param. def_id . as_local ( ) . map ( |def_id| {
1713
+ // Get the `hir::Param` to verify whether it already has any bounds.
1714
+ // We do this to avoid suggesting code that ends up as `T: 'a'b`,
1715
+ // instead we suggest `T: 'a + 'b` in that case.
1716
+ let id = hir. as_local_hir_id ( def_id) ;
1717
+ let mut has_bounds = false ;
1718
+ if let Node :: GenericParam ( param) = hir. get ( id) {
1719
+ has_bounds = !param. bounds . is_empty ( ) ;
1720
+ }
1721
+ let sp = hir. span ( id) ;
1722
+ // `sp` only covers `T`, change it so that it covers
1723
+ // `T:` when appropriate
1724
+ let is_impl_trait = bound_kind. to_string ( ) . starts_with ( "impl " ) ;
1725
+ let sp = if has_bounds && !is_impl_trait {
1726
+ sp. to ( self
1727
+ . tcx
1728
+ . sess
1729
+ . source_map ( )
1730
+ . next_point ( self . tcx . sess . source_map ( ) . next_point ( sp) ) )
1731
+ } else {
1732
+ sp
1733
+ } ;
1734
+ ( sp, has_bounds, is_impl_trait)
1735
+ } )
1736
+ } else {
1737
+ None
1738
+ }
1725
1739
}
1726
1740
_ => None ,
1727
1741
} ;
1742
+ let new_lt = generics
1743
+ . as_ref ( )
1744
+ . and_then ( |( parent_g, g) | {
1745
+ let possible: Vec < _ > = ( b'a' ..=b'z' ) . map ( |c| format ! ( "'{}" , c as char ) ) . collect ( ) ;
1746
+ let mut lts_names = g
1747
+ . params
1748
+ . iter ( )
1749
+ . filter ( |p| matches ! ( p. kind, ty:: GenericParamDefKind :: Lifetime ) )
1750
+ . map ( |p| p. name . as_str ( ) )
1751
+ . collect :: < Vec < _ > > ( ) ;
1752
+ if let Some ( g) = parent_g {
1753
+ lts_names. extend (
1754
+ g. params
1755
+ . iter ( )
1756
+ . filter ( |p| matches ! ( p. kind, ty:: GenericParamDefKind :: Lifetime ) )
1757
+ . map ( |p| p. name . as_str ( ) ) ,
1758
+ ) ;
1759
+ }
1760
+ let lts = lts_names. iter ( ) . map ( |s| -> & str { & * s } ) . collect :: < Vec < _ > > ( ) ;
1761
+ possible. into_iter ( ) . find ( |candidate| !lts. contains ( & candidate. as_str ( ) ) )
1762
+ } )
1763
+ . unwrap_or ( "'lt" . to_string ( ) ) ;
1764
+ let add_lt_sugg = generics
1765
+ . as_ref ( )
1766
+ . and_then ( |( _, g) | g. params . first ( ) )
1767
+ . and_then ( |param| param. def_id . as_local ( ) )
1768
+ . map ( |def_id| {
1769
+ ( hir. span ( hir. as_local_hir_id ( def_id) ) . shrink_to_lo ( ) , format ! ( "{}, " , new_lt) )
1770
+ } ) ;
1728
1771
1729
1772
let labeled_user_string = match bound_kind {
1730
1773
GenericKind :: Param ( ref p) => format ! ( "the parameter type `{}`" , p) ,
@@ -1781,6 +1824,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1781
1824
}
1782
1825
}
1783
1826
1827
+ let new_binding_suggestion =
1828
+ |err : & mut DiagnosticBuilder < ' tcx > ,
1829
+ type_param_span : Option < ( Span , bool , bool ) > ,
1830
+ bound_kind : GenericKind < ' tcx > | {
1831
+ let msg = "consider introducing an explicit lifetime bound" ;
1832
+ if let Some ( ( sp, has_lifetimes, is_impl_trait) ) = type_param_span {
1833
+ let suggestion = if is_impl_trait {
1834
+ ( sp. shrink_to_hi ( ) , format ! ( " + {}" , new_lt) )
1835
+ } else {
1836
+ let tail = if has_lifetimes { " +" } else { "" } ;
1837
+ ( sp, format ! ( "{}: {}{}" , bound_kind, new_lt, tail) )
1838
+ } ;
1839
+ let mut sugg =
1840
+ vec ! [ suggestion, ( span. shrink_to_hi( ) , format!( " + {}" , new_lt) ) ] ;
1841
+ if let Some ( lt) = add_lt_sugg {
1842
+ sugg. push ( lt) ;
1843
+ sugg. rotate_right ( 1 ) ;
1844
+ }
1845
+ // `MaybeIncorrect` due to issue #41966.
1846
+ err. multipart_suggestion ( msg, sugg, Applicability :: MaybeIncorrect ) ;
1847
+ }
1848
+ } ;
1849
+
1784
1850
let mut err = match * sub {
1785
1851
ty:: ReEarlyBound ( ty:: EarlyBoundRegion { name, .. } )
1786
1852
| ty:: ReFree ( ty:: FreeRegion { bound_region : ty:: BrNamed ( _, name) , .. } ) => {
@@ -1822,17 +1888,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1822
1888
"{} may not live long enough" ,
1823
1889
labeled_user_string
1824
1890
) ;
1825
- err. help ( & format ! (
1826
- "consider adding an explicit lifetime bound for `{}`" ,
1827
- bound_kind
1828
- ) ) ;
1829
1891
note_and_explain_region (
1830
1892
self . tcx ,
1831
1893
& mut err,
1832
1894
& format ! ( "{} must be valid for " , labeled_user_string) ,
1833
1895
sub,
1834
1896
"..." ,
1835
1897
) ;
1898
+ if let Some ( infer:: RelateParamBound ( _, t) ) = origin {
1899
+ let t = self . resolve_vars_if_possible ( & t) ;
1900
+ match t. kind {
1901
+ // We've got:
1902
+ // fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
1903
+ // suggest:
1904
+ // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
1905
+ ty:: Closure ( _, _substs) | ty:: Opaque ( _, _substs) => {
1906
+ new_binding_suggestion ( & mut err, type_param_span, bound_kind) ;
1907
+ }
1908
+ _ => {
1909
+ binding_suggestion ( & mut err, type_param_span, bound_kind, new_lt) ;
1910
+ }
1911
+ }
1912
+ }
1836
1913
err
1837
1914
}
1838
1915
} ;
@@ -1861,14 +1938,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1861
1938
"..." ,
1862
1939
) ;
1863
1940
1941
+ debug ! ( "report_sub_sup_conflict: var_origin={:?}" , var_origin) ;
1942
+ debug ! ( "report_sub_sup_conflict: sub_region={:?}" , sub_region) ;
1943
+ debug ! ( "report_sub_sup_conflict: sub_origin={:?}" , sub_origin) ;
1944
+ debug ! ( "report_sub_sup_conflict: sup_region={:?}" , sup_region) ;
1945
+ debug ! ( "report_sub_sup_conflict: sup_origin={:?}" , sup_origin) ;
1946
+
1864
1947
if let ( & infer:: Subtype ( ref sup_trace) , & infer:: Subtype ( ref sub_trace) ) =
1865
1948
( & sup_origin, & sub_origin)
1866
1949
{
1867
- debug ! ( "report_sub_sup_conflict: var_origin={:?}" , var_origin) ;
1868
- debug ! ( "report_sub_sup_conflict: sub_region={:?}" , sub_region) ;
1869
- debug ! ( "report_sub_sup_conflict: sub_origin={:?}" , sub_origin) ;
1870
- debug ! ( "report_sub_sup_conflict: sup_region={:?}" , sup_region) ;
1871
- debug ! ( "report_sub_sup_conflict: sup_origin={:?}" , sup_origin) ;
1872
1950
debug ! ( "report_sub_sup_conflict: sup_trace={:?}" , sup_trace) ;
1873
1951
debug ! ( "report_sub_sup_conflict: sub_trace={:?}" , sub_trace) ;
1874
1952
debug ! ( "report_sub_sup_conflict: sup_trace.values={:?}" , sup_trace. values) ;
0 commit comments