@@ -5178,8 +5178,10 @@ impl<'a> Parser<'a> {
51785178 /// Parses (possibly empty) list of lifetime and type parameters, possibly including
51795179 /// trailing comma and erroneous trailing attributes.
51805180 crate fn parse_generic_params ( & mut self ) -> PResult < ' a , Vec < ast:: GenericParam > > {
5181+ let mut lifetimes = Vec :: new ( ) ;
51815182 let mut params = Vec :: new ( ) ;
5182- let mut seen_ty_param = false ;
5183+ let mut seen_ty_param: Option < Span > = None ;
5184+ let mut last_comma_span = None ;
51835185 loop {
51845186 let attrs = self . parse_outer_attributes ( ) ?;
51855187 if self . check_lifetime ( ) {
@@ -5190,25 +5192,48 @@ impl<'a> Parser<'a> {
51905192 } else {
51915193 Vec :: new ( )
51925194 } ;
5193- params . push ( ast:: GenericParam {
5195+ lifetimes . push ( ast:: GenericParam {
51945196 ident : lifetime. ident ,
51955197 id : lifetime. id ,
51965198 attrs : attrs. into ( ) ,
51975199 bounds,
51985200 kind : ast:: GenericParamKind :: Lifetime ,
51995201 } ) ;
5200- if seen_ty_param {
5201- self . span_err ( self . prev_span ,
5202- "lifetime parameters must be declared prior to type parameters" ) ;
5202+ if let Some ( sp) = seen_ty_param {
5203+ let param_span = self . prev_span ;
5204+ let ate_comma = self . eat ( & token:: Comma ) ;
5205+ let remove_sp = if ate_comma {
5206+ param_span. until ( self . span )
5207+ } else {
5208+ last_comma_span. unwrap_or ( param_span) . to ( param_span)
5209+ } ;
5210+ let mut err = self . struct_span_err (
5211+ self . prev_span ,
5212+ "lifetime parameters must be declared prior to type parameters" ,
5213+ ) ;
5214+ if let Ok ( snippet) = self . sess . source_map ( ) . span_to_snippet ( param_span) {
5215+ err. multipart_suggestion (
5216+ "move the lifetime parameter prior to the first type parameter" ,
5217+ vec ! [
5218+ ( remove_sp, String :: new( ) ) ,
5219+ ( sp. shrink_to_lo( ) , format!( "{}, " , snippet) ) ,
5220+ ] ,
5221+ ) ;
5222+ }
5223+ err. emit ( ) ;
5224+ if ate_comma {
5225+ last_comma_span = Some ( self . prev_span ) ;
5226+ continue
5227+ }
52035228 }
52045229 } else if self . check_ident ( ) {
52055230 // Parse type parameter.
52065231 params. push ( self . parse_ty_param ( attrs) ?) ;
5207- seen_ty_param = true ;
5232+ seen_ty_param = Some ( self . prev_span ) ;
52085233 } else {
52095234 // Check for trailing attributes and stop parsing.
52105235 if !attrs. is_empty ( ) {
5211- let param_kind = if seen_ty_param { "type" } else { "lifetime" } ;
5236+ let param_kind = if seen_ty_param. is_some ( ) { "type" } else { "lifetime" } ;
52125237 self . span_err ( attrs[ 0 ] . span ,
52135238 & format ! ( "trailing attribute after {} parameters" , param_kind) ) ;
52145239 }
@@ -5218,8 +5243,10 @@ impl<'a> Parser<'a> {
52185243 if !self . eat ( & token:: Comma ) {
52195244 break
52205245 }
5246+ last_comma_span = Some ( self . prev_span ) ;
52215247 }
5222- Ok ( params)
5248+ lifetimes. extend ( params) ; // ensure the correct order of lifetimes and type params
5249+ Ok ( lifetimes)
52235250 }
52245251
52255252 /// Parse a set of optional generic type parameter declarations. Where
0 commit comments