@@ -774,10 +774,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
774774 bound_kind : GenericKind < ' tcx > ,
775775 sub : Region < ' tcx > )
776776 {
777- // FIXME: it would be better to report the first error message
778- // with the span of the parameter itself, rather than the span
779- // where the error was detected. But that span is not readily
780- // accessible.
777+ // Attempt to obtain the span of the parameter so we can
778+ // suggest adding an explicit lifetime bound to it.
779+ let type_param_span = match ( self . in_progress_tables , bound_kind) {
780+ ( Some ( ref table) , GenericKind :: Param ( ref param) ) => {
781+ let table = table. borrow ( ) ;
782+ table. local_id_root . and_then ( |did| {
783+ let generics = self . tcx . generics_of ( did) ;
784+ // Account for the case where `did` corresponds to `Self`, which doesn't have
785+ // the expected type argument.
786+ if generics. types . len ( ) > 0 {
787+ let type_param = generics. type_param ( param) ;
788+ let hir = & self . tcx . hir ;
789+ hir. as_local_node_id ( type_param. def_id ) . map ( |id| {
790+ // Get the `hir::TyParam` to verify wether it already has any bounds.
791+ // We do this to avoid suggesting code that ends up as `T: 'a'b`,
792+ // instead we suggest `T: 'a + 'b` in that case.
793+ let has_lifetimes = if let hir_map:: NodeTyParam ( ref p) = hir. get ( id) {
794+ p. bounds . len ( ) > 0
795+ } else {
796+ false
797+ } ;
798+ let sp = hir. span ( id) ;
799+ // `sp` only covers `T`, change it so that it covers
800+ // `T:` when appropriate
801+ let sp = if has_lifetimes {
802+ sp. to ( sp. next_point ( ) . next_point ( ) )
803+ } else {
804+ sp
805+ } ;
806+ ( sp, has_lifetimes)
807+ } )
808+ } else {
809+ None
810+ }
811+ } )
812+ }
813+ _ => None ,
814+ } ;
781815
782816 let labeled_user_string = match bound_kind {
783817 GenericKind :: Param ( ref p) =>
@@ -799,6 +833,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
799833 return ;
800834 }
801835
836+ fn binding_suggestion < ' tcx , S : fmt:: Display > ( err : & mut DiagnosticBuilder < ' tcx > ,
837+ type_param_span : Option < ( Span , bool ) > ,
838+ bound_kind : GenericKind < ' tcx > ,
839+ sub : S ) {
840+ let consider = & format ! ( "consider adding an explicit lifetime bound `{}: {}`..." ,
841+ bound_kind,
842+ sub) ;
843+ if let Some ( ( sp, has_lifetimes) ) = type_param_span {
844+ let tail = if has_lifetimes {
845+ " + "
846+ } else {
847+ ""
848+ } ;
849+ let suggestion = format ! ( "{}: {}{}" , bound_kind, sub, tail) ;
850+ err. span_suggestion_short ( sp, consider, suggestion) ;
851+ } else {
852+ err. help ( consider) ;
853+ }
854+ }
855+
802856 let mut err = match * sub {
803857 ty:: ReEarlyBound ( _) |
804858 ty:: ReFree ( ty:: FreeRegion { bound_region : ty:: BrNamed ( ..) , ..} ) => {
@@ -808,9 +862,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
808862 E0309 ,
809863 "{} may not live long enough" ,
810864 labeled_user_string) ;
811- err. help ( & format ! ( "consider adding an explicit lifetime bound `{}: {}`..." ,
812- bound_kind,
813- sub) ) ;
865+ binding_suggestion ( & mut err, type_param_span, bound_kind, sub) ;
814866 err
815867 }
816868
@@ -821,9 +873,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
821873 E0310 ,
822874 "{} may not live long enough" ,
823875 labeled_user_string) ;
824- err. help ( & format ! ( "consider adding an explicit lifetime \
825- bound `{}: 'static`...",
826- bound_kind) ) ;
876+ binding_suggestion ( & mut err, type_param_span, bound_kind, "'static" ) ;
827877 err
828878 }
829879
0 commit comments