@@ -5530,22 +5530,31 @@ impl<'a> Parser<'a> {
5530
5530
fn parse_generic_args ( & mut self ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
5531
5531
let mut args = Vec :: new ( ) ;
5532
5532
let mut bindings = Vec :: new ( ) ;
5533
+
5533
5534
let mut seen_type = false ;
5534
5535
let mut seen_binding = false ;
5536
+
5537
+ let mut last_comma_span = None ;
5535
5538
let mut first_type_or_binding_span: Option < Span > = None ;
5539
+ let mut first_binding_span: Option < Span > = None ;
5540
+
5536
5541
let mut bad_lifetime_pos = vec ! [ ] ;
5537
- let mut last_comma_span = None ;
5538
- let mut suggestions = vec ! [ ] ;
5542
+ let mut bad_type_pos = vec ! [ ] ;
5543
+
5544
+ let mut lifetime_suggestions = vec ! [ ] ;
5545
+ let mut type_suggestions = vec ! [ ] ;
5539
5546
loop {
5540
5547
if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| !t. is_like_plus ( ) ) {
5541
5548
// Parse lifetime argument.
5542
5549
args. push ( GenericArg :: Lifetime ( self . expect_lifetime ( ) ) ) ;
5550
+
5543
5551
if seen_type || seen_binding {
5544
5552
let remove_sp = last_comma_span. unwrap_or ( self . prev_span ) . to ( self . prev_span ) ;
5545
5553
bad_lifetime_pos. push ( self . prev_span ) ;
5554
+
5546
5555
if let Ok ( snippet) = self . sess . source_map ( ) . span_to_snippet ( self . prev_span ) {
5547
- suggestions . push ( ( remove_sp, String :: new ( ) ) ) ;
5548
- suggestions . push ( (
5556
+ lifetime_suggestions . push ( ( remove_sp, String :: new ( ) ) ) ;
5557
+ lifetime_suggestions . push ( (
5549
5558
first_type_or_binding_span. unwrap ( ) . shrink_to_lo ( ) ,
5550
5559
format ! ( "{}, " , snippet) ) ) ;
5551
5560
}
@@ -5563,24 +5572,29 @@ impl<'a> Parser<'a> {
5563
5572
ty,
5564
5573
span,
5565
5574
} ) ;
5575
+
5566
5576
seen_binding = true ;
5567
5577
if first_type_or_binding_span. is_none ( ) {
5568
5578
first_type_or_binding_span = Some ( span) ;
5569
5579
}
5580
+ if first_binding_span. is_none ( ) {
5581
+ first_binding_span = Some ( span) ;
5582
+ }
5570
5583
} else if self . check_type ( ) {
5571
5584
// Parse type argument.
5572
5585
let ty_param = self . parse_ty ( ) ?;
5573
5586
if seen_binding {
5574
- self . struct_span_err (
5575
- ty_param . span ,
5576
- "type parameters must be declared prior to associated type bindings"
5577
- )
5578
- . span_label (
5579
- ty_param . span ,
5580
- "must be declared prior to associated type bindings" ,
5581
- )
5582
- . emit ( ) ;
5587
+ let remove_sp = last_comma_span . unwrap_or ( self . prev_span ) . to ( self . prev_span ) ;
5588
+ bad_type_pos . push ( self . prev_span ) ;
5589
+
5590
+ if let Ok ( snippet ) = self . sess . source_map ( ) . span_to_snippet ( self . prev_span ) {
5591
+ type_suggestions . push ( ( remove_sp , String :: new ( ) ) ) ;
5592
+ type_suggestions . push ( (
5593
+ first_binding_span . unwrap ( ) . shrink_to_lo ( ) ,
5594
+ format ! ( "{}, " , snippet ) ) ) ;
5595
+ }
5583
5596
}
5597
+
5584
5598
if first_type_or_binding_span. is_none ( ) {
5585
5599
first_type_or_binding_span = Some ( ty_param. span ) ;
5586
5600
}
@@ -5596,6 +5610,7 @@ impl<'a> Parser<'a> {
5596
5610
last_comma_span = Some ( self . prev_span ) ;
5597
5611
}
5598
5612
}
5613
+
5599
5614
if !bad_lifetime_pos. is_empty ( ) {
5600
5615
let mut err = self . struct_span_err (
5601
5616
bad_lifetime_pos. clone ( ) ,
@@ -5604,18 +5619,40 @@ impl<'a> Parser<'a> {
5604
5619
for sp in & bad_lifetime_pos {
5605
5620
err. span_label ( * sp, "must be declared prior to type parameters" ) ;
5606
5621
}
5607
- if !suggestions . is_empty ( ) {
5622
+ if !lifetime_suggestions . is_empty ( ) {
5608
5623
err. multipart_suggestion_with_applicability (
5609
5624
& format ! (
5610
5625
"move the lifetime parameter{} prior to the first type parameter" ,
5611
5626
if bad_lifetime_pos. len( ) > 1 { "s" } else { "" } ,
5612
5627
) ,
5613
- suggestions ,
5628
+ lifetime_suggestions ,
5614
5629
Applicability :: MachineApplicable ,
5615
5630
) ;
5616
5631
}
5617
5632
err. emit ( ) ;
5618
5633
}
5634
+
5635
+ if !bad_type_pos. is_empty ( ) {
5636
+ let mut err = self . struct_span_err (
5637
+ bad_type_pos. clone ( ) ,
5638
+ "type parameters must be declared prior to associated type bindings"
5639
+ ) ;
5640
+ for sp in & bad_type_pos {
5641
+ err. span_label ( * sp, "must be declared prior to associated type bindings" ) ;
5642
+ }
5643
+ if !type_suggestions. is_empty ( ) {
5644
+ err. multipart_suggestion_with_applicability (
5645
+ & format ! (
5646
+ "move the type parameter{} prior to the first associated type binding" ,
5647
+ if bad_type_pos. len( ) > 1 { "s" } else { "" } ,
5648
+ ) ,
5649
+ type_suggestions,
5650
+ Applicability :: MachineApplicable ,
5651
+ ) ;
5652
+ }
5653
+ err. emit ( ) ;
5654
+ }
5655
+
5619
5656
Ok ( ( args, bindings) )
5620
5657
}
5621
5658
0 commit comments