@@ -5330,37 +5330,46 @@ impl<'a> Parser<'a> {
5330
5330
5331
5331
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
5332
5332
/// possibly including trailing comma.
5333
- fn parse_generic_args ( & mut self )
5334
- -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
5333
+ fn parse_generic_args ( & mut self ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
5335
5334
let mut args = Vec :: new ( ) ;
5336
5335
let mut bindings = Vec :: new ( ) ;
5337
5336
let mut seen_type = false ;
5338
5337
let mut seen_binding = false ;
5338
+ let mut first_type_or_binding_span: Option < Span > = None ;
5339
+ let mut bad_lifetime_pos = vec ! [ ] ;
5340
+ let mut last_comma_span = None ;
5341
+ let mut suggestions = vec ! [ ] ;
5339
5342
loop {
5340
5343
if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| !t. is_like_plus ( ) ) {
5341
5344
// Parse lifetime argument.
5342
5345
args. push ( GenericArg :: Lifetime ( self . expect_lifetime ( ) ) ) ;
5343
5346
if seen_type || seen_binding {
5344
- self . struct_span_err (
5345
- self . prev_span ,
5346
- "lifetime parameters must be declared prior to type parameters"
5347
- )
5348
- . span_label ( self . prev_span , "must be declared prior to type parameters" )
5349
- . emit ( ) ;
5347
+ let remove_sp = last_comma_span. unwrap_or ( self . prev_span ) . to ( self . prev_span ) ;
5348
+ bad_lifetime_pos. push ( self . prev_span ) ;
5349
+ if let Ok ( snippet) = self . sess . source_map ( ) . span_to_snippet ( self . prev_span ) {
5350
+ suggestions. push ( ( remove_sp, String :: new ( ) ) ) ;
5351
+ suggestions. push ( (
5352
+ first_type_or_binding_span. unwrap ( ) . shrink_to_lo ( ) ,
5353
+ format ! ( "{}, " , snippet) ) ) ;
5354
+ }
5350
5355
}
5351
5356
} else if self . check_ident ( ) && self . look_ahead ( 1 , |t| t == & token:: Eq ) {
5352
5357
// Parse associated type binding.
5353
5358
let lo = self . span ;
5354
5359
let ident = self . parse_ident ( ) ?;
5355
5360
self . bump ( ) ;
5356
5361
let ty = self . parse_ty ( ) ?;
5362
+ let span = lo. to ( self . prev_span ) ;
5357
5363
bindings. push ( TypeBinding {
5358
5364
id : ast:: DUMMY_NODE_ID ,
5359
5365
ident,
5360
5366
ty,
5361
- span : lo . to ( self . prev_span ) ,
5367
+ span,
5362
5368
} ) ;
5363
5369
seen_binding = true ;
5370
+ if first_type_or_binding_span. is_none ( ) {
5371
+ first_type_or_binding_span = Some ( span) ;
5372
+ }
5364
5373
} else if self . check_type ( ) {
5365
5374
// Parse type argument.
5366
5375
let ty_param = self . parse_ty ( ) ?;
@@ -5375,6 +5384,9 @@ impl<'a> Parser<'a> {
5375
5384
)
5376
5385
. emit ( ) ;
5377
5386
}
5387
+ if first_type_or_binding_span. is_none ( ) {
5388
+ first_type_or_binding_span = Some ( ty_param. span ) ;
5389
+ }
5378
5390
args. push ( GenericArg :: Type ( ty_param) ) ;
5379
5391
seen_type = true ;
5380
5392
} else {
@@ -5383,8 +5395,30 @@ impl<'a> Parser<'a> {
5383
5395
5384
5396
if !self . eat ( & token:: Comma ) {
5385
5397
break
5398
+ } else {
5399
+ last_comma_span = Some ( self . prev_span ) ;
5386
5400
}
5387
5401
}
5402
+ if !bad_lifetime_pos. is_empty ( ) {
5403
+ let mut err = self . struct_span_err (
5404
+ bad_lifetime_pos. clone ( ) ,
5405
+ "lifetime parameters must be declared prior to type parameters"
5406
+ ) ;
5407
+ for sp in & bad_lifetime_pos {
5408
+ err. span_label ( * sp, "must be declared prior to type parameters" ) ;
5409
+ }
5410
+ if !suggestions. is_empty ( ) {
5411
+ err. multipart_suggestion_with_applicability (
5412
+ & format ! (
5413
+ "move the lifetime parameter{} prior to the first type parameter" ,
5414
+ if bad_lifetime_pos. len( ) > 1 { "s" } else { "" } ,
5415
+ ) ,
5416
+ suggestions,
5417
+ Applicability :: MachineApplicable ,
5418
+ ) ;
5419
+ }
5420
+ err. emit ( ) ;
5421
+ }
5388
5422
Ok ( ( args, bindings) )
5389
5423
}
5390
5424
0 commit comments