@@ -1682,49 +1682,70 @@ 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- } )
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+ }
17251725 }
17261726 _ => None ,
17271727 } ;
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+ } ) ;
17281749
17291750 let labeled_user_string = match bound_kind {
17301751 GenericKind :: Param ( ref p) => format ! ( "the parameter type `{}`" , p) ,
@@ -1781,6 +1802,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17811802 }
17821803 }
17831804
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+
17841829 let mut err = match * sub {
17851830 ty:: ReEarlyBound ( ty:: EarlyBoundRegion { name, .. } )
17861831 | ty:: ReFree ( ty:: FreeRegion { bound_region : ty:: BrNamed ( _, name) , .. } ) => {
@@ -1822,17 +1867,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
18221867 "{} may not live long enough" ,
18231868 labeled_user_string
18241869 ) ;
1825- err. help ( & format ! (
1826- "consider adding an explicit lifetime bound for `{}`" ,
1827- bound_kind
1828- ) ) ;
18291870 note_and_explain_region (
18301871 self . tcx ,
18311872 & mut err,
18321873 & format ! ( "{} must be valid for " , labeled_user_string) ,
18331874 sub,
18341875 "..." ,
18351876 ) ;
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+ }
18361892 err
18371893 }
18381894 } ;
0 commit comments