@@ -774,10 +774,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
774
774
bound_kind : GenericKind < ' tcx > ,
775
775
sub : Region < ' tcx > )
776
776
{
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
+ } ;
781
815
782
816
let labeled_user_string = match bound_kind {
783
817
GenericKind :: Param ( ref p) =>
@@ -799,6 +833,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
799
833
return ;
800
834
}
801
835
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
+
802
856
let mut err = match * sub {
803
857
ty:: ReEarlyBound ( _) |
804
858
ty:: ReFree ( ty:: FreeRegion { bound_region : ty:: BrNamed ( ..) , ..} ) => {
@@ -808,9 +862,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
808
862
E0309 ,
809
863
"{} may not live long enough" ,
810
864
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) ;
814
866
err
815
867
}
816
868
@@ -821,9 +873,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
821
873
E0310 ,
822
874
"{} may not live long enough" ,
823
875
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" ) ;
827
877
err
828
878
}
829
879
0 commit comments