@@ -5530,22 +5530,31 @@ impl<'a> Parser<'a> {
55305530 fn parse_generic_args ( & mut self ) -> PResult < ' a , ( Vec < GenericArg > , Vec < TypeBinding > ) > {
55315531 let mut args = Vec :: new ( ) ;
55325532 let mut bindings = Vec :: new ( ) ;
5533+
55335534 let mut seen_type = false ;
55345535 let mut seen_binding = false ;
5536+
5537+ let mut last_comma_span = None ;
55355538 let mut first_type_or_binding_span: Option < Span > = None ;
5539+ let mut first_binding_span: Option < Span > = None ;
5540+
55365541 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 ! [ ] ;
55395546 loop {
55405547 if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| !t. is_like_plus ( ) ) {
55415548 // Parse lifetime argument.
55425549 args. push ( GenericArg :: Lifetime ( self . expect_lifetime ( ) ) ) ;
5550+
55435551 if seen_type || seen_binding {
55445552 let remove_sp = last_comma_span. unwrap_or ( self . prev_span ) . to ( self . prev_span ) ;
55455553 bad_lifetime_pos. push ( self . prev_span ) ;
5554+
55465555 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 ( (
55495558 first_type_or_binding_span. unwrap ( ) . shrink_to_lo ( ) ,
55505559 format ! ( "{}, " , snippet) ) ) ;
55515560 }
@@ -5563,24 +5572,29 @@ impl<'a> Parser<'a> {
55635572 ty,
55645573 span,
55655574 } ) ;
5575+
55665576 seen_binding = true ;
55675577 if first_type_or_binding_span. is_none ( ) {
55685578 first_type_or_binding_span = Some ( span) ;
55695579 }
5580+ if first_binding_span. is_none ( ) {
5581+ first_binding_span = Some ( span) ;
5582+ }
55705583 } else if self . check_type ( ) {
55715584 // Parse type argument.
55725585 let ty_param = self . parse_ty ( ) ?;
55735586 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+ }
55835596 }
5597+
55845598 if first_type_or_binding_span. is_none ( ) {
55855599 first_type_or_binding_span = Some ( ty_param. span ) ;
55865600 }
@@ -5596,6 +5610,7 @@ impl<'a> Parser<'a> {
55965610 last_comma_span = Some ( self . prev_span ) ;
55975611 }
55985612 }
5613+
55995614 if !bad_lifetime_pos. is_empty ( ) {
56005615 let mut err = self . struct_span_err (
56015616 bad_lifetime_pos. clone ( ) ,
@@ -5604,18 +5619,40 @@ impl<'a> Parser<'a> {
56045619 for sp in & bad_lifetime_pos {
56055620 err. span_label ( * sp, "must be declared prior to type parameters" ) ;
56065621 }
5607- if !suggestions . is_empty ( ) {
5622+ if !lifetime_suggestions . is_empty ( ) {
56085623 err. multipart_suggestion_with_applicability (
56095624 & format ! (
56105625 "move the lifetime parameter{} prior to the first type parameter" ,
56115626 if bad_lifetime_pos. len( ) > 1 { "s" } else { "" } ,
56125627 ) ,
5613- suggestions ,
5628+ lifetime_suggestions ,
56145629 Applicability :: MachineApplicable ,
56155630 ) ;
56165631 }
56175632 err. emit ( ) ;
56185633 }
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+
56195656 Ok ( ( args, bindings) )
56205657 }
56215658
0 commit comments