@@ -60,7 +60,7 @@ use rustc_errors::{pluralize, struct_span_err};
6060use rustc_errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString } ;
6161use rustc_hir as hir;
6262use rustc_hir:: def_id:: DefId ;
63- use rustc_hir:: Node ;
63+ use rustc_hir:: { Item , ItemKind , Node } ;
6464use rustc_middle:: ty:: error:: TypeError ;
6565use rustc_middle:: ty:: {
6666 self ,
@@ -1682,49 +1682,92 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16821682 bound_kind : GenericKind < ' tcx > ,
16831683 sub : Region < ' tcx > ,
16841684 ) -> DiagnosticBuilder < ' a > {
1685+ let hir = & self . tcx . hir ( ) ;
16851686 // Attempt to obtain the span of the parameter so we can
16861687 // 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 ( ) ) )
17211700 } else {
17221701 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+ }
17251739 }
17261740 _ => None ,
17271741 } ;
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+ } ) ;
17281771
17291772 let labeled_user_string = match bound_kind {
17301773 GenericKind :: Param ( ref p) => format ! ( "the parameter type `{}`" , p) ,
@@ -1781,6 +1824,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17811824 }
17821825 }
17831826
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+
17841850 let mut err = match * sub {
17851851 ty:: ReEarlyBound ( ty:: EarlyBoundRegion { name, .. } )
17861852 | ty:: ReFree ( ty:: FreeRegion { bound_region : ty:: BrNamed ( _, name) , .. } ) => {
@@ -1822,17 +1888,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
18221888 "{} may not live long enough" ,
18231889 labeled_user_string
18241890 ) ;
1825- err. help ( & format ! (
1826- "consider adding an explicit lifetime bound for `{}`" ,
1827- bound_kind
1828- ) ) ;
18291891 note_and_explain_region (
18301892 self . tcx ,
18311893 & mut err,
18321894 & format ! ( "{} must be valid for " , labeled_user_string) ,
18331895 sub,
18341896 "..." ,
18351897 ) ;
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+ }
18361913 err
18371914 }
18381915 } ;
@@ -1861,14 +1938,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
18611938 "..." ,
18621939 ) ;
18631940
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+
18641947 if let ( & infer:: Subtype ( ref sup_trace) , & infer:: Subtype ( ref sub_trace) ) =
18651948 ( & sup_origin, & sub_origin)
18661949 {
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) ;
18721950 debug ! ( "report_sub_sup_conflict: sup_trace={:?}" , sup_trace) ;
18731951 debug ! ( "report_sub_sup_conflict: sub_trace={:?}" , sub_trace) ;
18741952 debug ! ( "report_sub_sup_conflict: sup_trace.values={:?}" , sup_trace. values) ;
0 commit comments