6
6
// This pass is supposed to perform only simple checks not requiring name resolution
7
7
// or type checking or some other kind of complex analysis.
8
8
9
+ use itertools:: { Either , Itertools } ;
9
10
use rustc_ast:: ast:: * ;
10
11
use rustc_ast:: attr;
11
12
use rustc_ast:: expand:: is_proc_macro_attr;
@@ -14,7 +15,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
14
15
use rustc_ast:: walk_list;
15
16
use rustc_ast_pretty:: pprust;
16
17
use 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 } ;
18
19
use rustc_parse:: validate_attr;
19
20
use rustc_session:: lint:: builtin:: PATTERNS_IN_FNS_WITHOUT_BODY ;
20
21
use rustc_session:: lint:: LintBuffer ;
@@ -640,31 +641,70 @@ impl<'a> AstValidator<'a> {
640
641
}
641
642
}
642
643
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
+
643
671
/// Enforce generic args coming before constraints in `<...>` of a path segment.
644
672
fn check_generic_args_before_constraints ( & self , data : & AngleBracketedArgs ) {
645
673
// Early exit in case it's partitioned as it should be.
646
674
if data. args . iter ( ) . is_partitioned ( |arg| matches ! ( arg, AngleBracketedArg :: Arg ( _) ) ) {
647
675
return ;
648
676
}
649
677
// 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 ( ) ;
660
685
// ...and then error:
661
686
self . err_handler ( )
662
687
. struct_span_err (
663
- misplaced_args . clone ( ) ,
688
+ arg_spans . clone ( ) ,
664
689
"generic arguments must come before the first constraint" ,
665
690
)
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
+ )
668
708
. emit ( ) ;
669
709
}
670
710
}
0 commit comments