66// This pass is supposed to perform only simple checks not requiring name resolution
77// or type checking or some other kind of complex analysis.
88
9+ use itertools:: { Either , Itertools } ;
910use rustc_ast:: ast:: * ;
1011use rustc_ast:: attr;
1112use rustc_ast:: expand:: is_proc_macro_attr;
@@ -14,7 +15,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
1415use rustc_ast:: walk_list;
1516use rustc_ast_pretty:: pprust;
1617use rustc_data_structures:: fx:: FxHashMap ;
17- use rustc_errors:: { error_code, struct_span_err, Applicability } ;
18+ use rustc_errors:: { error_code, pluralize , struct_span_err, Applicability } ;
1819use rustc_parse:: validate_attr;
1920use rustc_session:: lint:: builtin:: PATTERNS_IN_FNS_WITHOUT_BODY ;
2021use rustc_session:: lint:: LintBuffer ;
@@ -640,31 +641,70 @@ impl<'a> AstValidator<'a> {
640641 }
641642 }
642643
644+ fn correct_generic_order_suggestion ( & self , data : & AngleBracketedArgs ) -> String {
645+ // Lifetimes always come first.
646+ let lt_sugg = data. args . iter ( ) . filter_map ( |arg| match arg {
647+ AngleBracketedArg :: Arg ( lt @ GenericArg :: Lifetime ( _) ) => {
648+ Some ( pprust:: to_string ( |s| s. print_generic_arg ( lt) ) )
649+ }
650+ _ => None ,
651+ } ) ;
652+ let args_sugg = data. args . iter ( ) . filter_map ( |a| match a {
653+ AngleBracketedArg :: Arg ( GenericArg :: Lifetime ( _) ) | AngleBracketedArg :: Constraint ( _) => {
654+ None
655+ }
656+ AngleBracketedArg :: Arg ( arg) => Some ( pprust:: to_string ( |s| s. print_generic_arg ( arg) ) ) ,
657+ } ) ;
658+ // Constraints always come last.
659+ let constraint_sugg = data. args . iter ( ) . filter_map ( |a| match a {
660+ AngleBracketedArg :: Arg ( _) => None ,
661+ AngleBracketedArg :: Constraint ( c) => {
662+ Some ( pprust:: to_string ( |s| s. print_assoc_constraint ( c) ) )
663+ }
664+ } ) ;
665+ format ! (
666+ "<{}>" ,
667+ lt_sugg. chain( args_sugg) . chain( constraint_sugg) . collect:: <Vec <String >>( ) . join( ", " )
668+ )
669+ }
670+
643671 /// Enforce generic args coming before constraints in `<...>` of a path segment.
644672 fn check_generic_args_before_constraints ( & self , data : & AngleBracketedArgs ) {
645673 // Early exit in case it's partitioned as it should be.
646674 if data. args . iter ( ) . is_partitioned ( |arg| matches ! ( arg, AngleBracketedArg :: Arg ( _) ) ) {
647675 return ;
648676 }
649677 // Find all generic argument coming after the first constraint...
650- let mut misplaced_args = Vec :: new ( ) ;
651- let mut first = None ;
652- for arg in & data. args {
653- match ( arg, first) {
654- ( AngleBracketedArg :: Arg ( a) , Some ( _) ) => misplaced_args. push ( a. span ( ) ) ,
655- ( AngleBracketedArg :: Constraint ( c) , None ) => first = Some ( c. span ) ,
656- ( AngleBracketedArg :: Arg ( _) , None ) | ( AngleBracketedArg :: Constraint ( _) , Some ( _) ) => {
657- }
658- }
659- }
678+ let ( constraint_spans, arg_spans) : ( Vec < Span > , Vec < Span > ) =
679+ data. args . iter ( ) . partition_map ( |arg| match arg {
680+ AngleBracketedArg :: Constraint ( c) => Either :: Left ( c. span ) ,
681+ AngleBracketedArg :: Arg ( a) => Either :: Right ( a. span ( ) ) ,
682+ } ) ;
683+ let args_len = arg_spans. len ( ) ;
684+ let constraint_len = constraint_spans. len ( ) ;
660685 // ...and then error:
661686 self . err_handler ( )
662687 . struct_span_err (
663- misplaced_args . clone ( ) ,
688+ arg_spans . clone ( ) ,
664689 "generic arguments must come before the first constraint" ,
665690 )
666- . span_label ( first. unwrap ( ) , "the first constraint is provided here" )
667- . span_labels ( misplaced_args, "generic argument" )
691+ . span_label ( constraint_spans[ 0 ] , & format ! ( "constraint{}" , pluralize!( constraint_len) ) )
692+ . span_label (
693+ * arg_spans. iter ( ) . last ( ) . unwrap ( ) ,
694+ & format ! ( "generic argument{}" , pluralize!( args_len) ) ,
695+ )
696+ . span_labels ( constraint_spans, "" )
697+ . span_labels ( arg_spans, "" )
698+ . span_suggestion_verbose (
699+ data. span ,
700+ & format ! (
701+ "move the constraint{} after the generic argument{}" ,
702+ pluralize!( constraint_len) ,
703+ pluralize!( args_len)
704+ ) ,
705+ self . correct_generic_order_suggestion ( & data) ,
706+ Applicability :: MachineApplicable ,
707+ )
668708 . emit ( ) ;
669709 }
670710}
0 commit comments