7
7
// or type checking or some other kind of complex analysis.
8
8
9
9
use std:: mem;
10
+ use syntax:: print:: pprust;
10
11
use rustc:: lint;
11
12
use rustc:: session:: Session ;
13
+ use rustc_data_structures:: fx:: FxHashMap ;
12
14
use syntax:: ast:: * ;
13
15
use syntax:: attr;
14
16
use syntax:: source_map:: Spanned ;
@@ -271,7 +273,74 @@ impl<'a> AstValidator<'a> {
271
273
_ => None ,
272
274
}
273
275
}
276
+ }
274
277
278
+ enum GenericPosition {
279
+ Param ,
280
+ Arg ,
281
+ }
282
+
283
+ fn validate_generics_order < ' a > (
284
+ handler : & errors:: Handler ,
285
+ generics : impl Iterator < Item = ( ParamKindOrd , Span , Option < String > ) > ,
286
+ pos : GenericPosition ,
287
+ span : Span ,
288
+ ) {
289
+ let mut max_param: Option < ParamKindOrd > = None ;
290
+ let mut out_of_order = FxHashMap :: default ( ) ;
291
+ let mut param_idents = vec ! [ ] ;
292
+
293
+ for ( kind, span, ident) in generics {
294
+ if let Some ( ident) = ident {
295
+ param_idents. push ( ( kind, param_idents. len ( ) , ident) ) ;
296
+ }
297
+ let max_param = & mut max_param;
298
+ match max_param {
299
+ Some ( max_param) if * max_param > kind => {
300
+ let entry = out_of_order. entry ( kind) . or_insert ( ( * max_param, vec ! [ ] ) ) ;
301
+ entry. 1 . push ( span) ;
302
+ }
303
+ Some ( _) | None => * max_param = Some ( kind) ,
304
+ } ;
305
+ }
306
+
307
+ let mut ordered_params = "<" . to_string ( ) ;
308
+ if !out_of_order. is_empty ( ) {
309
+ param_idents. sort_by_key ( |& ( po, i, _) | ( po, i) ) ;
310
+ let mut first = true ;
311
+ for ( _, _, ident) in param_idents {
312
+ if !first {
313
+ ordered_params += ", " ;
314
+ }
315
+ ordered_params += & ident;
316
+ first = false ;
317
+ }
318
+ }
319
+ ordered_params += ">" ;
320
+
321
+ let pos_str = match pos {
322
+ GenericPosition :: Param => "parameter" ,
323
+ GenericPosition :: Arg => "argument" ,
324
+ } ;
325
+
326
+ for ( param_ord, ( max_param, spans) ) in out_of_order {
327
+ let mut err = handler. struct_span_err ( spans,
328
+ & format ! (
329
+ "{} {pos}s must be declared prior to {} {pos}s" ,
330
+ param_ord,
331
+ max_param,
332
+ pos = pos_str,
333
+ ) ) ;
334
+ if let GenericPosition :: Param = pos {
335
+ err. span_suggestion (
336
+ span,
337
+ & format ! ( "reorder the {}s: lifetimes, then types, then consts" , pos_str) ,
338
+ ordered_params. clone ( ) ,
339
+ Applicability :: MachineApplicable ,
340
+ ) ;
341
+ }
342
+ err. emit ( ) ;
343
+ }
275
344
}
276
345
277
346
impl < ' a > Visitor < ' a > for AstValidator < ' a > {
@@ -412,6 +481,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
412
481
. note ( "only trait implementations may be annotated with default" ) . emit ( ) ;
413
482
}
414
483
}
484
+ ItemKind :: Fn ( _, header, ref generics, _) => {
485
+ // We currently do not permit const generics in `const fn`, as
486
+ // this is tantamount to allowing compile-time dependent typing.
487
+ if header. constness . node == Constness :: Const {
488
+ // Look for const generics and error if we find any.
489
+ for param in & generics. params {
490
+ match param. kind {
491
+ GenericParamKind :: Const { .. } => {
492
+ self . err_handler ( )
493
+ . struct_span_err (
494
+ item. span ,
495
+ "const parameters are not permitted in `const fn`" ,
496
+ )
497
+ . emit ( ) ;
498
+ }
499
+ _ => { }
500
+ }
501
+ }
502
+ }
503
+ }
415
504
ItemKind :: ForeignMod ( ..) => {
416
505
self . invalid_visibility (
417
506
& item. vis ,
@@ -508,6 +597,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
508
597
match * generic_args {
509
598
GenericArgs :: AngleBracketed ( ref data) => {
510
599
walk_list ! ( self , visit_generic_arg, & data. args) ;
600
+ validate_generics_order ( self . err_handler ( ) , data. args . iter ( ) . map ( |arg| {
601
+ ( match arg {
602
+ GenericArg :: Lifetime ( ..) => ParamKindOrd :: Lifetime ,
603
+ GenericArg :: Type ( ..) => ParamKindOrd :: Type ,
604
+ GenericArg :: Const ( ..) => ParamKindOrd :: Const ,
605
+ } , arg. span ( ) , None )
606
+ } ) , GenericPosition :: Arg , generic_args. span ( ) ) ;
511
607
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
512
608
// are allowed to contain nested `impl Trait`.
513
609
self . with_impl_trait ( None , |this| {
@@ -526,34 +622,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
526
622
}
527
623
528
624
fn visit_generics ( & mut self , generics : & ' a Generics ) {
529
- let mut seen_non_lifetime_param = false ;
530
- let mut seen_default = None ;
625
+ let mut prev_ty_default = None ;
531
626
for param in & generics. params {
532
- match ( & param. kind , seen_non_lifetime_param) {
533
- ( GenericParamKind :: Lifetime { .. } , true ) => {
627
+ if let GenericParamKind :: Type { ref default, .. } = param. kind {
628
+ if default. is_some ( ) {
629
+ prev_ty_default = Some ( param. ident . span ) ;
630
+ } else if let Some ( span) = prev_ty_default {
534
631
self . err_handler ( )
535
- . span_err ( param. ident . span , "lifetime parameters must be leading" ) ;
536
- } ,
537
- ( GenericParamKind :: Lifetime { .. } , false ) => { }
538
- ( GenericParamKind :: Type { ref default, .. } , _) => {
539
- seen_non_lifetime_param = true ;
540
- if default. is_some ( ) {
541
- seen_default = Some ( param. ident . span ) ;
542
- } else if let Some ( span) = seen_default {
543
- self . err_handler ( )
544
- . span_err ( span, "type parameters with a default must be trailing" ) ;
545
- break ;
546
- }
632
+ . span_err ( span, "type parameters with a default must be trailing" ) ;
633
+ break ;
547
634
}
548
635
}
549
636
}
637
+
638
+ validate_generics_order ( self . err_handler ( ) , generics. params . iter ( ) . map ( |param| {
639
+ let span = param. ident . span ;
640
+ let ident = Some ( param. ident . to_string ( ) ) ;
641
+ match & param. kind {
642
+ GenericParamKind :: Lifetime { .. } => ( ParamKindOrd :: Lifetime , span, ident) ,
643
+ GenericParamKind :: Type { .. } => ( ParamKindOrd :: Type , span, ident) ,
644
+ GenericParamKind :: Const { ref ty } => {
645
+ let ty = pprust:: ty_to_string ( ty) ;
646
+ ( ParamKindOrd :: Const , span, Some ( format ! ( "const {}: {}" , param. ident, ty) ) )
647
+ }
648
+ }
649
+ } ) , GenericPosition :: Param , generics. span ) ;
650
+
550
651
for predicate in & generics. where_clause . predicates {
551
652
if let WherePredicate :: EqPredicate ( ref predicate) = * predicate {
552
653
self . err_handler ( )
553
654
. span_err ( predicate. span , "equality constraints are not yet \
554
655
supported in where clauses (see #20041)") ;
555
656
}
556
657
}
658
+
557
659
visit:: walk_generics ( self , generics)
558
660
}
559
661
0 commit comments